@autorest/python 5.12.6 → 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 +205 -125
- package/autorest/black/__init__.py +3 -0
- package/autorest/codegen/__init__.py +120 -48
- package/autorest/codegen/models/__init__.py +2 -1
- package/autorest/codegen/models/base_schema.py +2 -6
- package/autorest/codegen/models/client.py +6 -0
- package/autorest/codegen/models/code_model.py +43 -74
- package/autorest/codegen/models/constant_schema.py +7 -7
- 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 +38 -10
- package/autorest/codegen/models/operation_group.py +7 -2
- package/autorest/codegen/models/paging_operation.py +3 -3
- package/autorest/codegen/models/parameter.py +71 -22
- package/autorest/codegen/models/parameter_list.py +11 -5
- 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 +17 -5
- package/autorest/codegen/models/schema_response.py +23 -10
- package/autorest/codegen/models/utils.py +20 -0
- package/autorest/codegen/serializers/__init__.py +184 -87
- package/autorest/codegen/serializers/builder_serializer.py +113 -47
- package/autorest/codegen/serializers/client_serializer.py +16 -6
- package/autorest/codegen/serializers/general_serializer.py +28 -4
- 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/CHANGELOG.md.jinja2 +6 -0
- package/autorest/codegen/templates/LICENSE.jinja2 +21 -0
- package/autorest/codegen/templates/MANIFEST.in.jinja2 +7 -0
- package/autorest/codegen/templates/README.md.jinja2 +105 -0
- package/autorest/codegen/templates/config.py.jinja2 +4 -4
- package/autorest/codegen/templates/dev_requirements.txt.jinja2 +10 -0
- 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 +20 -17
- 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/setup.py.jinja2 +79 -20
- 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/autorest/namer/name_converter.py +1 -1
- package/package.json +2 -2
- package/run-python3.js +1 -7
- package/venvtools.py +2 -2
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import logging
|
|
7
7
|
import sys
|
|
8
8
|
from typing import Dict, Any, Set, Union, List, Type
|
|
9
|
+
from pathlib import Path
|
|
9
10
|
import yaml
|
|
10
11
|
|
|
11
12
|
from .. import Plugin
|
|
@@ -17,7 +18,11 @@ from .models.parameter_list import GlobalParameterList
|
|
|
17
18
|
from .models.rest import Rest
|
|
18
19
|
from .serializers import JinjaSerializer
|
|
19
20
|
from .models.credential_schema_policy import CredentialSchemaPolicy, get_credential_schema_policy_type
|
|
20
|
-
from .models.
|
|
21
|
+
from .models.credential_schema_policy import BearerTokenCredentialPolicy, AzureKeyCredentialPolicy
|
|
22
|
+
from .models.credential_model import CredentialModel
|
|
23
|
+
|
|
24
|
+
_AAD_TYPE = "AADToken"
|
|
25
|
+
_KEY_TYPE = "AzureKey"
|
|
21
26
|
|
|
22
27
|
def _build_convenience_layer(yaml_data: Dict[str, Any], code_model: CodeModel) -> None:
|
|
23
28
|
# Create operations
|
|
@@ -31,7 +36,6 @@ def _build_convenience_layer(yaml_data: Dict[str, Any], code_model: CodeModel) -
|
|
|
31
36
|
code_model.sort_schemas()
|
|
32
37
|
|
|
33
38
|
if code_model.options["show_operations"]:
|
|
34
|
-
code_model.add_schema_link_to_operation()
|
|
35
39
|
code_model.generate_single_parameter_from_multiple_content_types_operation()
|
|
36
40
|
code_model.link_operation_to_request_builder()
|
|
37
41
|
# LRO operation
|
|
@@ -70,12 +74,33 @@ def _validate_code_model_options(options: Dict[str, Any]) -> None:
|
|
|
70
74
|
if options["basic_setup_py"] and not options["package_version"]:
|
|
71
75
|
raise ValueError("--basic-setup-py must be used with --package-version")
|
|
72
76
|
|
|
77
|
+
if options["package_mode"] and not options["package_version"]:
|
|
78
|
+
raise ValueError("--package-mode must be used with --package-version")
|
|
79
|
+
|
|
73
80
|
if not options["show_operations"] and options["combine_operation_files"]:
|
|
74
81
|
raise ValueError(
|
|
75
82
|
"Can not combine operation files if you are not showing operations. "
|
|
76
83
|
"If you want operation files, pass in flag --show-operations"
|
|
77
84
|
)
|
|
78
85
|
|
|
86
|
+
if options["package_mode"]:
|
|
87
|
+
if options["package_mode"] not in ("mgmtplane", "dataplane") and not Path(options["package_mode"]).exists():
|
|
88
|
+
raise ValueError(
|
|
89
|
+
"--package-mode can only be 'mgmtplane' or 'dataplane' or directory which contains template files"
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
if options["reformat_next_link"] and options["version_tolerant"]:
|
|
93
|
+
raise ValueError(
|
|
94
|
+
"--reformat-next-link can not be true for version tolerant generations. "
|
|
95
|
+
"Please remove --reformat-next-link from your call for version tolerant generations."
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
if options["multiapi"] and options["version_tolerant"]:
|
|
99
|
+
raise ValueError(
|
|
100
|
+
"Can not currently generate version tolerant multiapi SDKs. "
|
|
101
|
+
"We are working on creating a new multiapi SDK for version tolerant and it is not available yet."
|
|
102
|
+
)
|
|
103
|
+
|
|
79
104
|
_LOGGER = logging.getLogger(__name__)
|
|
80
105
|
class CodeGenerator(Plugin):
|
|
81
106
|
@staticmethod
|
|
@@ -111,28 +136,57 @@ class CodeGenerator(Plugin):
|
|
|
111
136
|
exceptions_set.add(id(exception["schema"]))
|
|
112
137
|
return exceptions_set
|
|
113
138
|
|
|
139
|
+
@staticmethod
|
|
140
|
+
def _build_package_dependency() -> Dict[str, str]:
|
|
141
|
+
return {
|
|
142
|
+
"dependency_azure_mgmt_core": "azure-mgmt-core<2.0.0,>=1.3.0",
|
|
143
|
+
"dependency_azure_core": "azure-core<2.0.0,>=1.23.0",
|
|
144
|
+
"dependency_msrest": "msrest>=0.6.21",
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
@staticmethod
|
|
148
|
+
def _build_with_security_definition(yaml_data: Dict[str, Any], credential_model: CredentialModel):
|
|
149
|
+
security_yaml = yaml_data.get("security", {})
|
|
150
|
+
if security_yaml.get("authenticationRequired"):
|
|
151
|
+
for scheme in security_yaml.get("schemes"):
|
|
152
|
+
if _AAD_TYPE == scheme["type"]:
|
|
153
|
+
credential_model.credential_scopes.update(scheme["scopes"])
|
|
154
|
+
elif _KEY_TYPE == scheme["type"]:
|
|
155
|
+
# only accept the last one
|
|
156
|
+
credential_model.key_header_name = scheme["headerName"]
|
|
157
|
+
|
|
158
|
+
if credential_model.credential_scopes:
|
|
159
|
+
credential_model.policy_type = BearerTokenCredentialPolicy
|
|
160
|
+
elif credential_model.key_header_name:
|
|
161
|
+
credential_model.policy_type = AzureKeyCredentialPolicy
|
|
162
|
+
|
|
163
|
+
@staticmethod
|
|
164
|
+
def _build_credential_model(code_model: CodeModel, credential_model: CredentialModel):
|
|
165
|
+
if credential_model.policy_type:
|
|
166
|
+
code_model.options["credential"] = True
|
|
167
|
+
credential_model.build_authentication_policy()
|
|
168
|
+
code_model.credential_model = credential_model
|
|
169
|
+
|
|
170
|
+
def _handle_credential_model(self, yaml_data: Dict[str, Any], code_model: CodeModel):
|
|
171
|
+
credential_model = CredentialModel(code_model.options["azure_arm"])
|
|
172
|
+
|
|
173
|
+
# credential info with security definition will be overridded by credential flags
|
|
174
|
+
self._build_with_security_definition(yaml_data, credential_model)
|
|
175
|
+
self._build_with_credential_flags(code_model, credential_model)
|
|
176
|
+
|
|
177
|
+
self._build_credential_model(code_model, credential_model)
|
|
178
|
+
|
|
114
179
|
def _create_code_model(self, yaml_data: Dict[str, Any], options: Dict[str, Union[str, bool]]) -> CodeModel:
|
|
115
180
|
# Create a code model
|
|
116
181
|
|
|
117
182
|
code_model = CodeModel(options=options)
|
|
118
|
-
|
|
119
|
-
self._handle_default_authentication_policy(code_model)
|
|
183
|
+
self._handle_credential_model(yaml_data, code_model)
|
|
120
184
|
code_model.module_name = yaml_data["info"]["python_title"]
|
|
121
185
|
code_model.class_name = yaml_data["info"]["pascal_case_title"]
|
|
122
186
|
code_model.description = (
|
|
123
187
|
yaml_data["info"]["description"] if yaml_data["info"].get("description") else ""
|
|
124
188
|
)
|
|
125
189
|
|
|
126
|
-
# Global parameters
|
|
127
|
-
code_model.global_parameters = GlobalParameterList(
|
|
128
|
-
code_model,
|
|
129
|
-
[Parameter.from_yaml(param, code_model=code_model) for param in yaml_data.get("globalParameters", [])],
|
|
130
|
-
)
|
|
131
|
-
code_model.global_parameters.code_model = code_model
|
|
132
|
-
|
|
133
|
-
# Custom URL
|
|
134
|
-
code_model.setup_client_input_parameters(yaml_data)
|
|
135
|
-
|
|
136
190
|
# Get my namespace
|
|
137
191
|
namespace = self._autorestapi.get_value("namespace")
|
|
138
192
|
_LOGGER.debug("Namespace parameter was %s", namespace)
|
|
@@ -140,21 +194,30 @@ class CodeGenerator(Plugin):
|
|
|
140
194
|
namespace = yaml_data["info"]["python_title"]
|
|
141
195
|
code_model.namespace = namespace
|
|
142
196
|
|
|
143
|
-
code_model.rest = Rest.from_yaml(yaml_data, code_model=code_model)
|
|
144
197
|
if yaml_data.get("schemas"):
|
|
145
198
|
exceptions_set = CodeGenerator._build_exceptions_set(yaml_data=yaml_data["operationGroups"])
|
|
146
199
|
|
|
147
200
|
for type_list in yaml_data["schemas"].values():
|
|
148
201
|
for schema in type_list:
|
|
149
202
|
build_schema(yaml_data=schema, exceptions_set=exceptions_set, code_model=code_model)
|
|
150
|
-
code_model.add_schema_link_to_request_builder()
|
|
151
|
-
code_model.add_schema_link_to_global_parameters()
|
|
152
203
|
|
|
204
|
+
# Global parameters
|
|
205
|
+
code_model.global_parameters = GlobalParameterList(
|
|
206
|
+
code_model,
|
|
207
|
+
[Parameter.from_yaml(param, code_model=code_model) for param in yaml_data.get("globalParameters", [])],
|
|
208
|
+
)
|
|
209
|
+
code_model.global_parameters.code_model = code_model
|
|
210
|
+
|
|
211
|
+
# Custom URL
|
|
212
|
+
code_model.setup_client_input_parameters(yaml_data)
|
|
213
|
+
|
|
214
|
+
code_model.rest = Rest.from_yaml(yaml_data, code_model=code_model)
|
|
153
215
|
_build_convenience_layer(yaml_data=yaml_data, code_model=code_model)
|
|
154
216
|
|
|
155
217
|
if options["credential"]:
|
|
156
218
|
code_model.global_parameters.add_credential_global_parameter()
|
|
157
219
|
|
|
220
|
+
code_model.package_dependency = self._build_package_dependency()
|
|
158
221
|
return code_model
|
|
159
222
|
|
|
160
223
|
def _get_credential_scopes(self, credential):
|
|
@@ -171,9 +234,13 @@ class CodeGenerator(Plugin):
|
|
|
171
234
|
)
|
|
172
235
|
return credential_scopes
|
|
173
236
|
|
|
174
|
-
def
|
|
175
|
-
self,
|
|
176
|
-
|
|
237
|
+
def _update_with_credential_flags(
|
|
238
|
+
self,
|
|
239
|
+
code_model: CodeModel,
|
|
240
|
+
credential_schema_policy: Type[CredentialSchemaPolicy],
|
|
241
|
+
credential_model: CredentialModel
|
|
242
|
+
):
|
|
243
|
+
credential_model.policy_type = credential_schema_policy
|
|
177
244
|
credential_scopes = self._get_credential_scopes(code_model.options['credential'])
|
|
178
245
|
credential_key_header_name = self._autorestapi.get_value('credential-key-header-name')
|
|
179
246
|
azure_arm = code_model.options['azure_arm']
|
|
@@ -202,38 +269,36 @@ class CodeGenerator(Plugin):
|
|
|
202
269
|
"name is tied with AzureKeyCredentialPolicy. Instead, with this policy it is recommend you "
|
|
203
270
|
"pass in --credential-scopes."
|
|
204
271
|
)
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
272
|
+
credential_model.credential_scopes = set(credential_scopes)
|
|
273
|
+
else:
|
|
274
|
+
# currently the only other credential policy is AzureKeyCredentialPolicy
|
|
275
|
+
if credential_scopes:
|
|
276
|
+
raise ValueError(
|
|
277
|
+
"You have passed in credential scopes with default credential policy type "
|
|
278
|
+
"AzureKeyCredentialPolicy. This is not allowed, since credential scopes is tied with "
|
|
279
|
+
f"{credential_model.default_authentication_policy.name()}. Instead, with this policy "
|
|
280
|
+
"you must pass in --credential-key-header-name."
|
|
281
|
+
)
|
|
282
|
+
if not credential_key_header_name:
|
|
283
|
+
credential_key_header_name = "api-key"
|
|
284
|
+
_LOGGER.info(
|
|
285
|
+
"Defaulting the AzureKeyCredentialPolicy header's name to 'api-key'"
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
credential_model.key_header_name = credential_key_header_name
|
|
289
|
+
|
|
290
|
+
def _build_with_credential_flags(self, code_model: CodeModel, credential_model: CredentialModel):
|
|
291
|
+
if not code_model.options["credential"]:
|
|
292
|
+
return
|
|
226
293
|
|
|
227
|
-
def _handle_default_authentication_policy(self, code_model: CodeModel):
|
|
228
294
|
credential_schema_policy_name = (
|
|
229
295
|
self._autorestapi.get_value("credential-default-policy-type") or
|
|
230
|
-
|
|
296
|
+
credential_model.default_authentication_policy.name()
|
|
231
297
|
)
|
|
232
298
|
credential_schema_policy_type = get_credential_schema_policy_type(credential_schema_policy_name)
|
|
233
|
-
|
|
234
|
-
code_model, credential_schema_policy_type
|
|
299
|
+
self._update_with_credential_flags(
|
|
300
|
+
code_model, credential_schema_policy_type, credential_model
|
|
235
301
|
)
|
|
236
|
-
code_model.credential_schema_policy = credential_schema_policy
|
|
237
302
|
|
|
238
303
|
def _build_code_model_options(self) -> Dict[str, Any]:
|
|
239
304
|
"""Build en options dict from the user input while running autorest.
|
|
@@ -289,6 +354,13 @@ class CodeGenerator(Plugin):
|
|
|
289
354
|
"low_level_client": low_level_client,
|
|
290
355
|
"combine_operation_files": self._autorestapi.get_boolean_value("combine-operation-files", version_tolerant),
|
|
291
356
|
"python3_only": python3_only,
|
|
357
|
+
"package_mode": self._autorestapi.get_value("package-mode"),
|
|
358
|
+
"package_pprint_name": self._autorestapi.get_value("package-pprint-name"),
|
|
359
|
+
"package_configuration": self._autorestapi.get_value("package-configuration"),
|
|
360
|
+
"default_optional_constants_to_none": self._autorestapi.get_boolean_value(
|
|
361
|
+
"default-optional-constants-to-none", low_level_client or version_tolerant
|
|
362
|
+
),
|
|
363
|
+
"reformat_next_link": self._autorestapi.get_boolean_value("reformat-next-link", not version_tolerant)
|
|
292
364
|
}
|
|
293
365
|
|
|
294
366
|
if options["builders_visibility"] is None:
|
|
@@ -327,8 +399,8 @@ class CodeGenerator(Plugin):
|
|
|
327
399
|
|
|
328
400
|
code_model = self._create_code_model(yaml_data=yaml_data, options=options)
|
|
329
401
|
|
|
330
|
-
serializer = JinjaSerializer(self._autorestapi)
|
|
331
|
-
serializer.serialize(
|
|
402
|
+
serializer = JinjaSerializer(self._autorestapi, code_model)
|
|
403
|
+
serializer.serialize()
|
|
332
404
|
|
|
333
405
|
return True
|
|
334
406
|
|
|
@@ -17,7 +17,7 @@ from .constant_schema import ConstantSchema
|
|
|
17
17
|
from .imports import FileImport, ImportType, TypingSection
|
|
18
18
|
from .lro_operation import LROOperation
|
|
19
19
|
from .paging_operation import PagingOperation
|
|
20
|
-
from .parameter import Parameter, ParameterStyle
|
|
20
|
+
from .parameter import Parameter, ParameterStyle, ParameterLocation
|
|
21
21
|
from .operation import Operation
|
|
22
22
|
from .property import Property
|
|
23
23
|
from .operation_group import OperationGroup
|
|
@@ -50,6 +50,7 @@ __all__ = [
|
|
|
50
50
|
"PagingOperation",
|
|
51
51
|
"Parameter",
|
|
52
52
|
"ParameterList",
|
|
53
|
+
"ParameterLocation",
|
|
53
54
|
"OperationGroup",
|
|
54
55
|
"Property",
|
|
55
56
|
"RequestBuilder",
|
|
@@ -90,18 +90,14 @@ class BaseSchema(BaseModel, ABC):
|
|
|
90
90
|
"""
|
|
91
91
|
...
|
|
92
92
|
|
|
93
|
-
@
|
|
94
|
-
def type_annotation(self) -> str:
|
|
93
|
+
@abstractmethod
|
|
94
|
+
def type_annotation(self, *, is_operation_file: bool = False) -> str:
|
|
95
95
|
"""The python type used for type annotation
|
|
96
96
|
|
|
97
97
|
Special case for enum, for instance: Union[str, "EnumName"]
|
|
98
98
|
"""
|
|
99
99
|
...
|
|
100
100
|
|
|
101
|
-
@property
|
|
102
|
-
def operation_type_annotation(self) -> str:
|
|
103
|
-
return self.type_annotation
|
|
104
|
-
|
|
105
101
|
def get_declaration(self, value: Any) -> str: # pylint: disable=no-self-use
|
|
106
102
|
"""Return the current value from YAML as a Python string that represents the constant.
|
|
107
103
|
|
|
@@ -102,3 +102,9 @@ class Client:
|
|
|
102
102
|
def send_request_signature(self, is_python3_file: bool) -> List[str]:
|
|
103
103
|
request_signature = ["request: HttpRequest," if is_python3_file else "request, # type: HttpRequest"]
|
|
104
104
|
return request_signature + self.parameters.method_signature_kwargs(is_python3_file)
|
|
105
|
+
|
|
106
|
+
@property
|
|
107
|
+
def filename(self) -> str:
|
|
108
|
+
if self.code_model.options["version_tolerant"] or self.code_model.options["low_level_client"]:
|
|
109
|
+
return "_client"
|
|
110
|
+
return f"_{self.code_model.module_name}"
|
|
@@ -3,14 +3,10 @@
|
|
|
3
3
|
# Licensed under the MIT License. See License.txt in the project root for
|
|
4
4
|
# license information.
|
|
5
5
|
# --------------------------------------------------------------------------
|
|
6
|
-
from itertools import chain
|
|
7
6
|
import logging
|
|
8
|
-
from typing import cast, List, Dict, Optional, Any, Set
|
|
7
|
+
from typing import cast, List, Dict, Optional, Any, Set
|
|
9
8
|
|
|
10
9
|
from .base_schema import BaseSchema
|
|
11
|
-
from .credential_schema_policy import (
|
|
12
|
-
ARMChallengeAuthenticationPolicy, BearerTokenCredentialPolicy, CredentialSchemaPolicy
|
|
13
|
-
)
|
|
14
10
|
from .enum_schema import EnumSchema
|
|
15
11
|
from .object_schema import ObjectSchema
|
|
16
12
|
from .operation_group import OperationGroup
|
|
@@ -20,12 +16,10 @@ from .paging_operation import PagingOperation
|
|
|
20
16
|
from .parameter import Parameter
|
|
21
17
|
from .client import Client
|
|
22
18
|
from .parameter_list import GlobalParameterList
|
|
23
|
-
from .schema_response import SchemaResponse
|
|
24
19
|
from .property import Property
|
|
25
|
-
from .primitive_schemas import IOSchema
|
|
26
20
|
from .request_builder import RequestBuilder
|
|
27
21
|
from .rest import Rest
|
|
28
|
-
|
|
22
|
+
from .credential_model import CredentialModel
|
|
29
23
|
|
|
30
24
|
_LOGGER = logging.getLogger(__name__)
|
|
31
25
|
|
|
@@ -51,6 +45,10 @@ class CodeModel: # pylint: disable=too-many-instance-attributes, too-many-publi
|
|
|
51
45
|
:type primitives: Dict[int, ~autorest.models.BaseSchema]
|
|
52
46
|
:param operation_groups: The operation groups we are going to serialize
|
|
53
47
|
:type operation_groups: list[~autorest.models.OperationGroup]
|
|
48
|
+
:param package_dependency: All the dependencies needed in setup.py
|
|
49
|
+
:type package_dependency: Dict[str, str]
|
|
50
|
+
:param credential_model: The class contains all the credential info
|
|
51
|
+
:type credential_model: CredentialMode
|
|
54
52
|
"""
|
|
55
53
|
|
|
56
54
|
def __init__(
|
|
@@ -75,7 +73,8 @@ class CodeModel: # pylint: disable=too-many-instance-attributes, too-many-publi
|
|
|
75
73
|
self.service_client: Client = Client(self, params)
|
|
76
74
|
self._rest: Optional[Rest] = None
|
|
77
75
|
self.request_builder_ids: Dict[int, RequestBuilder] = {}
|
|
78
|
-
self.
|
|
76
|
+
self.package_dependency: Dict[str, str] = {}
|
|
77
|
+
self._credential_model: Optional[CredentialModel] = None
|
|
79
78
|
|
|
80
79
|
@property
|
|
81
80
|
def global_parameters(self) -> GlobalParameterList:
|
|
@@ -208,18 +207,14 @@ class CodeModel: # pylint: disable=too-many-instance-attributes, too-many-publi
|
|
|
208
207
|
return self.schemas or self.enums
|
|
209
208
|
|
|
210
209
|
@property
|
|
211
|
-
def
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
def credential_schema_policy(self) -> CredentialSchemaPolicy:
|
|
216
|
-
if not self._credential_schema_policy:
|
|
217
|
-
raise ValueError("You want to find the Credential Schema Policy, but have not given a value")
|
|
218
|
-
return self._credential_schema_policy
|
|
210
|
+
def credential_model(self) -> CredentialModel:
|
|
211
|
+
if not self._credential_model:
|
|
212
|
+
raise ValueError("You want to find the Credential Model, but have not given a value")
|
|
213
|
+
return self._credential_model
|
|
219
214
|
|
|
220
|
-
@
|
|
221
|
-
def
|
|
222
|
-
self.
|
|
215
|
+
@credential_model.setter
|
|
216
|
+
def credential_model(self, val: CredentialModel) -> None:
|
|
217
|
+
self._credential_model = val
|
|
223
218
|
|
|
224
219
|
@staticmethod
|
|
225
220
|
def _add_properties_from_inheritance_helper(schema, properties) -> List[Property]:
|
|
@@ -300,74 +295,33 @@ class CodeModel: # pylint: disable=too-many-instance-attributes, too-many-publi
|
|
|
300
295
|
return
|
|
301
296
|
raise KeyError("Didn't find the target property")
|
|
302
297
|
|
|
303
|
-
def _populate_schema(self, obj: Any) -> None:
|
|
304
|
-
schema_obj = obj.schema
|
|
305
|
-
if schema_obj and not isinstance(schema_obj, dict):
|
|
306
|
-
return
|
|
307
|
-
|
|
308
|
-
if schema_obj:
|
|
309
|
-
schema_obj_id = id(obj.schema)
|
|
310
|
-
_LOGGER.debug("Looking for id %s for member %s", schema_obj_id, obj)
|
|
311
|
-
try:
|
|
312
|
-
obj.schema = self.lookup_schema(schema_obj_id)
|
|
313
|
-
except KeyError:
|
|
314
|
-
_LOGGER.critical("Unable to ref the object")
|
|
315
|
-
raise
|
|
316
|
-
if isinstance(obj, Parameter) and obj.target_property_name:
|
|
317
|
-
self._populate_target_property(obj)
|
|
318
|
-
if isinstance(obj, SchemaResponse) and obj.is_stream_response:
|
|
319
|
-
obj.schema = IOSchema(namespace=None, yaml_data={})
|
|
320
|
-
|
|
321
|
-
def add_schema_link_to_operation(self) -> None:
|
|
322
|
-
"""Puts created schemas into operation classes `schema` property
|
|
323
|
-
|
|
324
|
-
:return: None
|
|
325
|
-
:rtype: None
|
|
326
|
-
"""
|
|
327
|
-
# Index schemas
|
|
328
|
-
for operation_group in self.operation_groups:
|
|
329
|
-
for operation in operation_group.operations:
|
|
330
|
-
for obj in chain(
|
|
331
|
-
operation.parameters,
|
|
332
|
-
operation.multiple_content_type_parameters or [],
|
|
333
|
-
operation.responses,
|
|
334
|
-
operation.exceptions,
|
|
335
|
-
chain.from_iterable(response.headers for response in operation.responses),
|
|
336
|
-
):
|
|
337
|
-
self._populate_schema(obj)
|
|
338
|
-
|
|
339
|
-
def add_schema_link_to_request_builder(self) -> None:
|
|
340
|
-
for request_builder in self.rest.request_builders:
|
|
341
|
-
for obj in chain(
|
|
342
|
-
request_builder.parameters,
|
|
343
|
-
chain.from_iterable(request.parameters for request in request_builder.schema_requests),
|
|
344
|
-
request_builder.responses,
|
|
345
|
-
):
|
|
346
|
-
self._populate_schema(obj)
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
def add_schema_link_to_global_parameters(self) -> None:
|
|
350
|
-
for parameter in self.global_parameters:
|
|
351
|
-
self._populate_schema(parameter)
|
|
352
|
-
|
|
353
298
|
def generate_single_parameter_from_multiple_content_types_operation(self) -> None:
|
|
354
299
|
for operation_group in self.operation_groups:
|
|
355
300
|
for operation in operation_group.operations:
|
|
356
301
|
if operation.multiple_content_type_parameters:
|
|
357
302
|
operation.convert_multiple_content_type_parameters()
|
|
358
303
|
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
304
|
+
def need_vendored_code(self, async_mode: bool) -> bool:
|
|
305
|
+
if async_mode:
|
|
306
|
+
return self.need_mixin_abc
|
|
307
|
+
return self.need_request_converter or self.need_format_url or self.need_mixin_abc
|
|
362
308
|
|
|
363
309
|
@property
|
|
364
310
|
def need_request_converter(self) -> bool:
|
|
365
|
-
return
|
|
311
|
+
return (
|
|
312
|
+
self.options["show_operations"] and
|
|
313
|
+
bool(self.rest.request_builders) and
|
|
314
|
+
not self.options["version_tolerant"]
|
|
315
|
+
)
|
|
366
316
|
|
|
367
317
|
@property
|
|
368
318
|
def need_format_url(self) -> bool:
|
|
369
319
|
return any(rq for rq in self.rest.request_builders if rq.parameters.path)
|
|
370
320
|
|
|
321
|
+
@property
|
|
322
|
+
def need_mixin_abc(self) -> bool:
|
|
323
|
+
return any(o for o in self.operation_groups if o.is_empty_operation_group and self.options["python3_only"])
|
|
324
|
+
|
|
371
325
|
@property
|
|
372
326
|
def has_lro_operations(self) -> bool:
|
|
373
327
|
return any([
|
|
@@ -397,3 +351,18 @@ class CodeModel: # pylint: disable=too-many-instance-attributes, too-many-publi
|
|
|
397
351
|
request_builder.name = request_builder.name + "_initial"
|
|
398
352
|
operation.request_builder = request_builder
|
|
399
353
|
operation.link_body_kwargs_to_body_params()
|
|
354
|
+
|
|
355
|
+
def get_models_filename(self, is_python3_file: bool) -> str:
|
|
356
|
+
if (
|
|
357
|
+
self.options["version_tolerant"] or self.options["low_level_client"]
|
|
358
|
+
) and self.options["python3_only"]:
|
|
359
|
+
return "_models"
|
|
360
|
+
if is_python3_file:
|
|
361
|
+
return "_models_py3"
|
|
362
|
+
return "_models"
|
|
363
|
+
|
|
364
|
+
@property
|
|
365
|
+
def enums_filename(self) -> str:
|
|
366
|
+
if self.options["version_tolerant"] or self.options["low_level_client"]:
|
|
367
|
+
return "_enums"
|
|
368
|
+
return f"_{self.module_name}_enums"
|
|
@@ -39,10 +39,6 @@ class ConstantSchema(BaseSchema):
|
|
|
39
39
|
return "None"
|
|
40
40
|
return self.schema.get_declaration(self.value)
|
|
41
41
|
|
|
42
|
-
@property
|
|
43
|
-
def extra_description_information(self) -> str:
|
|
44
|
-
return f"The default value is {self.get_declaration(self.value)}."
|
|
45
|
-
|
|
46
42
|
@property
|
|
47
43
|
def serialization_type(self) -> str:
|
|
48
44
|
"""Returns the serialization value for msrest.
|
|
@@ -64,9 +60,8 @@ class ConstantSchema(BaseSchema):
|
|
|
64
60
|
"""
|
|
65
61
|
return self.schema.docstring_type
|
|
66
62
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
return self.schema.type_annotation
|
|
63
|
+
def type_annotation(self, *, is_operation_file: bool = False) -> str:
|
|
64
|
+
return self.schema.type_annotation(is_operation_file=is_operation_file)
|
|
70
65
|
|
|
71
66
|
@classmethod
|
|
72
67
|
def from_yaml(cls, namespace: str, yaml_data: Dict[str, Any], **kwargs) -> "ConstantSchema":
|
|
@@ -99,3 +94,8 @@ class ConstantSchema(BaseSchema):
|
|
|
99
94
|
file_import = FileImport()
|
|
100
95
|
file_import.merge(self.schema.imports())
|
|
101
96
|
return file_import
|
|
97
|
+
|
|
98
|
+
def model_file_imports(self) -> FileImport:
|
|
99
|
+
file_import = self.imports()
|
|
100
|
+
file_import.merge(self.schema.model_file_imports())
|
|
101
|
+
return file_import
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# -------------------------------------------------------------------------
|
|
2
|
+
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
# Licensed under the MIT License. See License.txt in the project root for
|
|
4
|
+
# license information.
|
|
5
|
+
# --------------------------------------------------------------------------
|
|
6
|
+
from typing import Set, Optional, Type
|
|
7
|
+
from .credential_schema_policy import CredentialSchemaPolicy, BearerTokenCredentialPolicy
|
|
8
|
+
from .credential_schema_policy import ARMChallengeAuthenticationPolicy
|
|
9
|
+
from .credential_schema import TokenCredentialSchema, AzureKeyCredentialSchema
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class CredentialModel:
|
|
13
|
+
"""Store info about credential.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
def __init__(
|
|
17
|
+
self,
|
|
18
|
+
azure_arm: bool
|
|
19
|
+
) -> None:
|
|
20
|
+
self.azure_arm: bool = azure_arm
|
|
21
|
+
self.credential_scopes: Set[str] = set()
|
|
22
|
+
self.key_header_name: str = ""
|
|
23
|
+
self.policy_type: Optional[Type[CredentialSchemaPolicy]] = None
|
|
24
|
+
self._credential_schema_policy: Optional[CredentialSchemaPolicy] = None
|
|
25
|
+
|
|
26
|
+
@property
|
|
27
|
+
def default_authentication_policy(self) -> Type[CredentialSchemaPolicy]:
|
|
28
|
+
return ARMChallengeAuthenticationPolicy if self.azure_arm else BearerTokenCredentialPolicy
|
|
29
|
+
|
|
30
|
+
@property
|
|
31
|
+
def credential_schema_policy(self) -> CredentialSchemaPolicy:
|
|
32
|
+
if not self._credential_schema_policy:
|
|
33
|
+
raise ValueError(
|
|
34
|
+
"You want to find the Credential Schema Policy, but have not given a value")
|
|
35
|
+
return self._credential_schema_policy
|
|
36
|
+
|
|
37
|
+
def build_authentication_policy(self):
|
|
38
|
+
if hasattr(self.policy_type, "credential_scopes"):
|
|
39
|
+
self._credential_schema_policy = self.policy_type( # pylint: disable=not-callable
|
|
40
|
+
credential=TokenCredentialSchema(async_mode=False),
|
|
41
|
+
credential_scopes=list(self.credential_scopes),
|
|
42
|
+
)
|
|
43
|
+
elif hasattr(self.policy_type, "credential_key_header_name"):
|
|
44
|
+
self._credential_schema_policy = self.policy_type( # pylint: disable=not-callable
|
|
45
|
+
credential=AzureKeyCredentialSchema(),
|
|
46
|
+
credential_key_header_name=self.key_header_name
|
|
47
|
+
)
|
|
@@ -11,6 +11,9 @@ class CredentialSchema(BaseSchema):
|
|
|
11
11
|
def __init__(self) -> None: # pylint: disable=super-init-not-called
|
|
12
12
|
self.default_value = None
|
|
13
13
|
|
|
14
|
+
def type_annotation(self, *, is_operation_file: bool = False) -> str:
|
|
15
|
+
raise ValueError("Children classes should set their own type annotation")
|
|
16
|
+
|
|
14
17
|
@property
|
|
15
18
|
def docstring_type(self) -> str:
|
|
16
19
|
return self.serialization_type
|
|
@@ -38,8 +41,7 @@ class AzureKeyCredentialSchema(CredentialSchema):
|
|
|
38
41
|
def serialization_type(self) -> str:
|
|
39
42
|
return "~azure.core.credentials.AzureKeyCredential"
|
|
40
43
|
|
|
41
|
-
|
|
42
|
-
def type_annotation(self) -> str:
|
|
44
|
+
def type_annotation(self, *, is_operation_file: bool = False) -> str: # pylint: disable=unused-argument
|
|
43
45
|
return "AzureKeyCredential"
|
|
44
46
|
|
|
45
47
|
def imports(self) -> FileImport:
|
|
@@ -66,8 +68,7 @@ class TokenCredentialSchema(CredentialSchema):
|
|
|
66
68
|
return self.async_type
|
|
67
69
|
return self.sync_type
|
|
68
70
|
|
|
69
|
-
|
|
70
|
-
def type_annotation(self) -> str:
|
|
71
|
+
def type_annotation(self, *, is_operation_file: bool = False) -> str: # pylint: disable=unused-argument
|
|
71
72
|
if self.async_mode:
|
|
72
73
|
return '"AsyncTokenCredential"'
|
|
73
74
|
return '"TokenCredential"'
|
|
@@ -34,18 +34,13 @@ class DictionarySchema(BaseSchema):
|
|
|
34
34
|
"""
|
|
35
35
|
return f"{{{self.element_type.serialization_type}}}"
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
def type_annotation(self) -> str:
|
|
37
|
+
def type_annotation(self, *, is_operation_file: bool = False) -> str:
|
|
39
38
|
"""The python type used for type annotation
|
|
40
39
|
|
|
41
40
|
:return: The type annotation for this schema
|
|
42
41
|
:rtype: str
|
|
43
42
|
"""
|
|
44
|
-
return f"Dict[str, {self.element_type.type_annotation}]"
|
|
45
|
-
|
|
46
|
-
@property
|
|
47
|
-
def operation_type_annotation(self) -> str:
|
|
48
|
-
return f"Dict[str, {self.element_type.operation_type_annotation}]"
|
|
43
|
+
return f"Dict[str, {self.element_type.type_annotation(is_operation_file=is_operation_file)}]"
|
|
49
44
|
|
|
50
45
|
@property
|
|
51
46
|
def docstring_text(self) -> str:
|
|
@@ -101,3 +96,8 @@ class DictionarySchema(BaseSchema):
|
|
|
101
96
|
file_import.add_submodule_import("typing", "Dict", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
102
97
|
file_import.merge(self.element_type.imports())
|
|
103
98
|
return file_import
|
|
99
|
+
|
|
100
|
+
def model_file_imports(self) -> FileImport:
|
|
101
|
+
file_import = self.imports()
|
|
102
|
+
file_import.merge(self.element_type.model_file_imports())
|
|
103
|
+
return file_import
|