@autorest/python 6.0.0 → 6.0.1
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 +15 -0
- package/autorest/__init__.py +54 -13
- package/autorest/black/__init__.py +14 -8
- package/autorest/codegen/__init__.py +125 -77
- package/autorest/codegen/serializers/__init__.py +43 -48
- package/autorest/codegen/serializers/client_serializer.py +6 -0
- package/autorest/jsonrpc/server.py +7 -7
- package/autorest/m2r/__init__.py +7 -2
- package/autorest/m4reformatter/__init__.py +4 -2
- package/autorest/multiapi/__init__.py +56 -29
- package/autorest/multiapi/serializers/__init__.py +23 -23
- package/autorest/multiapi/serializers/multiapi_serializer.py +33 -26
- package/autorest/postprocess/__init__.py +14 -11
- package/autorest/preprocess/__init__.py +13 -4
- package/package.json +1 -1
package/ChangeLog.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Release History
|
|
2
2
|
|
|
3
|
+
### 2022-06-29 - 6.0.1
|
|
4
|
+
|
|
5
|
+
| Library | Min Version |
|
|
6
|
+
| ----------------------------------------------------------------------- | ----------- |
|
|
7
|
+
| `@autorest/core` | `3.8.1` |
|
|
8
|
+
| `@autorest/modelerfour` | `4.23.5` |
|
|
9
|
+
| `azure-core` dep of generated code | `1.24.0` |
|
|
10
|
+
| `isodate` dep of generated code | `0.6.1` |
|
|
11
|
+
| `msrest` dep of generated code (If generating legacy code) | `0.7.1` |
|
|
12
|
+
| `azure-mgmt-core` dep of generated code (If generating mgmt plane code) | `1.3.0` |
|
|
13
|
+
|
|
14
|
+
**Bug Fixes**
|
|
15
|
+
|
|
16
|
+
- Ignore linting error for clients with no credentials #1333
|
|
17
|
+
|
|
3
18
|
### 2022-06-24 - 6.0.0
|
|
4
19
|
|
|
5
20
|
| Library | Min Version |
|
package/autorest/__init__.py
CHANGED
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
# license information.
|
|
5
5
|
# --------------------------------------------------------------------------
|
|
6
6
|
import logging
|
|
7
|
+
from pathlib import Path
|
|
7
8
|
from abc import ABC, abstractmethod
|
|
8
|
-
from typing import Any, Dict
|
|
9
|
+
from typing import Any, Dict, Union
|
|
9
10
|
|
|
10
11
|
import yaml
|
|
11
12
|
|
|
@@ -17,14 +18,40 @@ __version__ = VERSION
|
|
|
17
18
|
_LOGGER = logging.getLogger(__name__)
|
|
18
19
|
|
|
19
20
|
|
|
20
|
-
class
|
|
21
|
+
class ReaderAndWriter:
|
|
22
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
def read_file(self, path: Union[str, Path]) -> str:
|
|
26
|
+
"""How does one read a file in cadl?"""
|
|
27
|
+
raise NotImplementedError("Haven't plugged in Cadl yet")
|
|
28
|
+
|
|
29
|
+
def write_file(self, filename: Union[str, Path], file_content: str) -> None:
|
|
30
|
+
"""How does writing work in cadl?"""
|
|
31
|
+
raise NotImplementedError("Haven't plugged in Cadl yet")
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ReaderAndWriterAutorest(ReaderAndWriter):
|
|
35
|
+
def __init__(self, *, autorestapi: AutorestAPI) -> None:
|
|
36
|
+
super().__init__()
|
|
37
|
+
self._autorestapi = autorestapi
|
|
38
|
+
|
|
39
|
+
def read_file(self, path: Union[str, Path]) -> str:
|
|
40
|
+
return self._autorestapi.read_file(path)
|
|
41
|
+
|
|
42
|
+
def write_file(self, filename: Union[str, Path], file_content: str) -> None:
|
|
43
|
+
return self._autorestapi.write_file(filename, file_content)
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class Plugin(ReaderAndWriter, ABC):
|
|
21
47
|
"""A base class for autorest plugin.
|
|
22
48
|
|
|
23
49
|
:param autorestapi: An autorest API instance
|
|
24
50
|
"""
|
|
25
51
|
|
|
26
|
-
def __init__(self,
|
|
27
|
-
|
|
52
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
53
|
+
super().__init__(**kwargs)
|
|
54
|
+
self.options: Dict[str, Any] = {}
|
|
28
55
|
|
|
29
56
|
@abstractmethod
|
|
30
57
|
def process(self) -> bool:
|
|
@@ -37,24 +64,30 @@ class Plugin(ABC):
|
|
|
37
64
|
raise NotImplementedError()
|
|
38
65
|
|
|
39
66
|
|
|
67
|
+
class PluginAutorest(Plugin, ReaderAndWriterAutorest):
|
|
68
|
+
"""For our Autorest plugins, we want to take autorest api as input as options, then pass it to the Plugin"""
|
|
69
|
+
|
|
70
|
+
def __init__(self, autorestapi: AutorestAPI) -> None:
|
|
71
|
+
super().__init__(autorestapi=autorestapi)
|
|
72
|
+
self.options = self.get_options()
|
|
73
|
+
|
|
74
|
+
@abstractmethod
|
|
75
|
+
def get_options(self) -> Dict[str, Any]:
|
|
76
|
+
"""Get the options bag using the AutorestAPI that we send to the parent plugin"""
|
|
77
|
+
|
|
78
|
+
|
|
40
79
|
class YamlUpdatePlugin(Plugin):
|
|
41
80
|
"""A plugin that update the YAML as input."""
|
|
42
81
|
|
|
43
82
|
def process(self) -> bool:
|
|
44
83
|
# List the input file, should be only one
|
|
45
|
-
|
|
46
|
-
_LOGGER.debug("Possible Inputs: %s", inputs)
|
|
47
|
-
if "code-model-v4-no-tags.yaml" not in inputs:
|
|
48
|
-
raise ValueError("code-model-v4-no-tags.yaml must be a possible input")
|
|
49
|
-
|
|
50
|
-
file_content = self._autorestapi.read_file("code-model-v4-no-tags.yaml")
|
|
51
|
-
yaml_data = yaml.safe_load(file_content)
|
|
84
|
+
yaml_data = yaml.safe_load(self.read_file("code-model-v4-no-tags.yaml"))
|
|
52
85
|
|
|
53
86
|
self.update_yaml(yaml_data)
|
|
54
87
|
|
|
55
88
|
yaml_string = yaml.safe_dump(yaml_data)
|
|
56
89
|
|
|
57
|
-
self.
|
|
90
|
+
self.write_file("code-model-v4-no-tags.yaml", yaml_string)
|
|
58
91
|
return True
|
|
59
92
|
|
|
60
93
|
@abstractmethod
|
|
@@ -67,4 +100,12 @@ class YamlUpdatePlugin(Plugin):
|
|
|
67
100
|
raise NotImplementedError()
|
|
68
101
|
|
|
69
102
|
|
|
70
|
-
|
|
103
|
+
class YamlUpdatePluginAutorest( # pylint: disable=abstract-method
|
|
104
|
+
YamlUpdatePlugin, PluginAutorest
|
|
105
|
+
):
|
|
106
|
+
def get_options(self) -> Dict[str, Any]:
|
|
107
|
+
inputs = self._autorestapi.list_inputs()
|
|
108
|
+
_LOGGER.debug("Possible Inputs: %s", inputs)
|
|
109
|
+
if "code-model-v4-no-tags.yaml" not in inputs:
|
|
110
|
+
raise ValueError("code-model-v4-no-tags.yaml must be a possible input")
|
|
111
|
+
return {}
|
|
@@ -6,9 +6,10 @@
|
|
|
6
6
|
import logging
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
import os
|
|
9
|
+
from typing import Any, Dict
|
|
9
10
|
import black
|
|
10
11
|
|
|
11
|
-
from .. import Plugin
|
|
12
|
+
from .. import Plugin, PluginAutorest
|
|
12
13
|
|
|
13
14
|
_LOGGER = logging.getLogger(__name__)
|
|
14
15
|
|
|
@@ -16,10 +17,10 @@ _BLACK_MODE = black.Mode()
|
|
|
16
17
|
_BLACK_MODE.line_length = 120
|
|
17
18
|
|
|
18
19
|
|
|
19
|
-
class BlackScriptPlugin(Plugin):
|
|
20
|
-
def __init__(self,
|
|
21
|
-
super().__init__(
|
|
22
|
-
output_folder_uri = self.
|
|
20
|
+
class BlackScriptPlugin(Plugin): # pylint: disable=abstract-method
|
|
21
|
+
def __init__(self, **kwargs):
|
|
22
|
+
super().__init__(**kwargs)
|
|
23
|
+
output_folder_uri = self.options["outputFolderUri"]
|
|
23
24
|
if output_folder_uri.startswith("file:"):
|
|
24
25
|
output_folder_uri = output_folder_uri[5:]
|
|
25
26
|
if os.name == "nt" and output_folder_uri.startswith("///"):
|
|
@@ -38,9 +39,9 @@ class BlackScriptPlugin(Plugin):
|
|
|
38
39
|
|
|
39
40
|
def format_file(self, full_path) -> None:
|
|
40
41
|
file = full_path.relative_to(self.output_folder)
|
|
41
|
-
file_content = self.
|
|
42
|
+
file_content = self.read_file(file)
|
|
42
43
|
if not file.suffix == ".py":
|
|
43
|
-
self.
|
|
44
|
+
self.write_file(file, file_content)
|
|
44
45
|
return
|
|
45
46
|
try:
|
|
46
47
|
file_content = black.format_file_contents(
|
|
@@ -48,4 +49,9 @@ class BlackScriptPlugin(Plugin):
|
|
|
48
49
|
)
|
|
49
50
|
except black.NothingChanged:
|
|
50
51
|
pass
|
|
51
|
-
self.
|
|
52
|
+
self.write_file(file, file_content)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class BlackScriptPluginAutorest(BlackScriptPlugin, PluginAutorest):
|
|
56
|
+
def get_options(self) -> Dict[str, Any]:
|
|
57
|
+
return {"outputFolderUri": self._autorestapi.get_value("outputFolderUri")}
|
|
@@ -10,13 +10,13 @@ from pathlib import Path
|
|
|
10
10
|
import yaml
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
from .. import Plugin
|
|
13
|
+
from .. import Plugin, PluginAutorest
|
|
14
14
|
from .models.client import Client, Config
|
|
15
15
|
from .models.code_model import CodeModel
|
|
16
16
|
from .models import build_type
|
|
17
17
|
from .models.request_builder import get_request_builder
|
|
18
18
|
from .models.operation_group import OperationGroup
|
|
19
|
-
from .serializers import JinjaSerializer
|
|
19
|
+
from .serializers import JinjaSerializer, JinjaSerializerAutorest
|
|
20
20
|
|
|
21
21
|
|
|
22
22
|
def _build_convenience_layer(yaml_data: Dict[str, Any], code_model: CodeModel) -> None:
|
|
@@ -162,8 +162,8 @@ class CodeGenerator(Plugin):
|
|
|
162
162
|
|
|
163
163
|
def _build_code_model_options(self) -> Dict[str, Any]:
|
|
164
164
|
"""Build en options dict from the user input while running autorest."""
|
|
165
|
-
azure_arm = self.
|
|
166
|
-
license_header = self.
|
|
165
|
+
azure_arm = self.options.get("azure-arm", False)
|
|
166
|
+
license_header = self.options["header-text"]
|
|
167
167
|
if license_header:
|
|
168
168
|
license_header = license_header.replace("\n", "\n# ")
|
|
169
169
|
license_header = (
|
|
@@ -172,83 +172,46 @@ class CodeGenerator(Plugin):
|
|
|
172
172
|
)
|
|
173
173
|
license_header += "\n# --------------------------------------------------------------------------"
|
|
174
174
|
|
|
175
|
-
low_level_client = cast(
|
|
176
|
-
|
|
177
|
-
)
|
|
178
|
-
version_tolerant = cast(
|
|
179
|
-
bool, self._autorestapi.get_boolean_value("version-tolerant")
|
|
180
|
-
)
|
|
181
|
-
show_operations = self._autorestapi.get_boolean_value(
|
|
182
|
-
"show-operations", not low_level_client
|
|
183
|
-
)
|
|
175
|
+
low_level_client = cast(bool, self.options.get("low-level-client", False))
|
|
176
|
+
version_tolerant = cast(bool, self.options.get("version-tolerant", True))
|
|
177
|
+
show_operations = self.options.get("show-operations", not low_level_client)
|
|
184
178
|
models_mode_default = (
|
|
185
179
|
"none" if low_level_client or version_tolerant else "msrest"
|
|
186
180
|
)
|
|
187
|
-
if self._autorestapi.get_boolean_value("python3-only") is False:
|
|
188
|
-
_LOGGER.warning(
|
|
189
|
-
"You have passed in --python3-only=False. We have force overriden "
|
|
190
|
-
"this to True."
|
|
191
|
-
)
|
|
192
|
-
if self._autorestapi.get_boolean_value("add-python3-operation-files"):
|
|
193
|
-
_LOGGER.warning(
|
|
194
|
-
"You have passed in --add-python3-operation-files. "
|
|
195
|
-
"This flag no longer has an effect bc all SDKs are now Python3 only."
|
|
196
|
-
)
|
|
197
|
-
if self._autorestapi.get_boolean_value("reformat-next-link"):
|
|
198
|
-
_LOGGER.warning(
|
|
199
|
-
"You have passed in --reformat-next-link. We have force overriden "
|
|
200
|
-
"this to False because we no longer reformat initial query parameters into next "
|
|
201
|
-
"calls unless explicitly defined in the service definition."
|
|
202
|
-
)
|
|
203
181
|
|
|
204
182
|
options: Dict[str, Any] = {
|
|
205
183
|
"azure_arm": azure_arm,
|
|
206
|
-
"head_as_boolean": self.
|
|
207
|
-
"head-as-boolean", False
|
|
208
|
-
),
|
|
184
|
+
"head_as_boolean": self.options.get("head-as-boolean", True),
|
|
209
185
|
"license_header": license_header,
|
|
210
|
-
"keep_version_file": self.
|
|
211
|
-
|
|
212
|
-
),
|
|
213
|
-
"
|
|
214
|
-
"
|
|
215
|
-
|
|
216
|
-
),
|
|
217
|
-
"
|
|
218
|
-
|
|
219
|
-
),
|
|
220
|
-
"
|
|
221
|
-
"
|
|
222
|
-
"client_side_validation": self._autorestapi.get_boolean_value(
|
|
223
|
-
"client-side-validation", False
|
|
224
|
-
),
|
|
225
|
-
"tracing": self._autorestapi.get_boolean_value("trace", show_operations),
|
|
226
|
-
"multiapi": self._autorestapi.get_boolean_value("multiapi", False),
|
|
227
|
-
"polymorphic_examples": self._autorestapi.get_value("polymorphic-examples")
|
|
228
|
-
or 5,
|
|
229
|
-
"models_mode": (
|
|
230
|
-
self._autorestapi.get_value("models-mode") or models_mode_default
|
|
231
|
-
).lower(),
|
|
232
|
-
"builders_visibility": self._autorestapi.get_value("builders-visibility"),
|
|
186
|
+
"keep_version_file": self.options.get("keep-version-file", False),
|
|
187
|
+
"no_async": self.options.get("no-async", False),
|
|
188
|
+
"no_namespace_folders": self.options.get("no-namespace-folders", False),
|
|
189
|
+
"basic_setup_py": self.options.get("basic-setup-py", False),
|
|
190
|
+
"package_name": self.options.get("package-name"),
|
|
191
|
+
"package_version": self.options.get("package-version"),
|
|
192
|
+
"client_side_validation": self.options.get("client-side-validation", False),
|
|
193
|
+
"tracing": self.options.get("tracing", show_operations),
|
|
194
|
+
"multiapi": self.options.get("multiapi", False),
|
|
195
|
+
"polymorphic_examples": self.options.get("polymorphic-examples", 5),
|
|
196
|
+
"models_mode": self.options.get("models-mode", models_mode_default).lower(),
|
|
197
|
+
"builders_visibility": self.options.get("builders-visibility"),
|
|
233
198
|
"show_operations": show_operations,
|
|
234
|
-
"show_send_request": self.
|
|
199
|
+
"show_send_request": self.options.get(
|
|
235
200
|
"show-send-request", low_level_client or version_tolerant
|
|
236
201
|
),
|
|
237
|
-
"only_path_and_body_params_positional": self.
|
|
202
|
+
"only_path_and_body_params_positional": self.options.get(
|
|
238
203
|
"only-path-and-body-params-positional",
|
|
239
204
|
low_level_client or version_tolerant,
|
|
240
205
|
),
|
|
241
206
|
"version_tolerant": version_tolerant,
|
|
242
207
|
"low_level_client": low_level_client,
|
|
243
|
-
"combine_operation_files": self.
|
|
208
|
+
"combine_operation_files": self.options.get(
|
|
244
209
|
"combine-operation-files", version_tolerant
|
|
245
210
|
),
|
|
246
|
-
"package_mode": self.
|
|
247
|
-
"package_pprint_name": self.
|
|
248
|
-
"package_configuration": self.
|
|
249
|
-
|
|
250
|
-
),
|
|
251
|
-
"default_optional_constants_to_none": self._autorestapi.get_boolean_value(
|
|
211
|
+
"package_mode": self.options.get("package-mode"),
|
|
212
|
+
"package_pprint_name": self.options.get("package-pprint-name"),
|
|
213
|
+
"package_configuration": self.options.get("package-configuration"),
|
|
214
|
+
"default_optional_constants_to_none": self.options.get(
|
|
252
215
|
"default-optional-constants-to-none",
|
|
253
216
|
low_level_client or version_tolerant,
|
|
254
217
|
),
|
|
@@ -272,8 +235,102 @@ class CodeGenerator(Plugin):
|
|
|
272
235
|
options["head_as_boolean"] = True
|
|
273
236
|
return options
|
|
274
237
|
|
|
238
|
+
def get_yaml(self) -> Dict[str, Any]:
|
|
239
|
+
# cadl should call this one
|
|
240
|
+
raise NotImplementedError()
|
|
241
|
+
|
|
242
|
+
@staticmethod
|
|
243
|
+
def get_serializer(code_model: CodeModel):
|
|
244
|
+
return JinjaSerializer(code_model)
|
|
245
|
+
|
|
275
246
|
def process(self) -> bool:
|
|
276
247
|
# List the input file, should be only one
|
|
248
|
+
|
|
249
|
+
options = self._build_code_model_options()
|
|
250
|
+
yaml_data = self.get_yaml()
|
|
251
|
+
|
|
252
|
+
if options["azure_arm"]:
|
|
253
|
+
self.remove_cloud_errors(yaml_data)
|
|
254
|
+
|
|
255
|
+
code_model = self._create_code_model(yaml_data=yaml_data, options=options)
|
|
256
|
+
|
|
257
|
+
serializer = self.get_serializer(code_model)
|
|
258
|
+
serializer.serialize()
|
|
259
|
+
|
|
260
|
+
return True
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
class CodeGeneratorAutorest(CodeGenerator, PluginAutorest):
|
|
264
|
+
def get_options(self) -> Dict[str, Any]:
|
|
265
|
+
if self._autorestapi.get_boolean_value("python3-only") is False:
|
|
266
|
+
_LOGGER.warning(
|
|
267
|
+
"You have passed in --python3-only=False. We have force overriden "
|
|
268
|
+
"this to True."
|
|
269
|
+
)
|
|
270
|
+
if self._autorestapi.get_boolean_value("add-python3-operation-files"):
|
|
271
|
+
_LOGGER.warning(
|
|
272
|
+
"You have passed in --add-python3-operation-files. "
|
|
273
|
+
"This flag no longer has an effect bc all SDKs are now Python3 only."
|
|
274
|
+
)
|
|
275
|
+
if self._autorestapi.get_boolean_value("reformat-next-link"):
|
|
276
|
+
_LOGGER.warning(
|
|
277
|
+
"You have passed in --reformat-next-link. We have force overriden "
|
|
278
|
+
"this to False because we no longer reformat initial query parameters into next "
|
|
279
|
+
"calls unless explicitly defined in the service definition."
|
|
280
|
+
)
|
|
281
|
+
options = {
|
|
282
|
+
"azure-arm": self._autorestapi.get_boolean_value("azure-arm"),
|
|
283
|
+
"header-text": self._autorestapi.get_value("header-text"),
|
|
284
|
+
"low-level-client": self._autorestapi.get_boolean_value(
|
|
285
|
+
"low-level-client", False
|
|
286
|
+
),
|
|
287
|
+
"version-tolerant": self._autorestapi.get_boolean_value(
|
|
288
|
+
"version-tolerant", True
|
|
289
|
+
),
|
|
290
|
+
"show-operations": self._autorestapi.get_boolean_value("show-operations"),
|
|
291
|
+
"python3-only": self._autorestapi.get_boolean_value("python3-only"),
|
|
292
|
+
"head-as-boolean": self._autorestapi.get_boolean_value(
|
|
293
|
+
"head-as-boolean", False
|
|
294
|
+
),
|
|
295
|
+
"keep-version-file": self._autorestapi.get_boolean_value(
|
|
296
|
+
"keep-version-file"
|
|
297
|
+
),
|
|
298
|
+
"no-async": self._autorestapi.get_boolean_value("no-async"),
|
|
299
|
+
"no-namespace-folders": self._autorestapi.get_boolean_value(
|
|
300
|
+
"no-namespace-folders"
|
|
301
|
+
),
|
|
302
|
+
"basic-setup-py": self._autorestapi.get_boolean_value("basic-setup-py"),
|
|
303
|
+
"package-name": self._autorestapi.get_value("package-name"),
|
|
304
|
+
"package-version": self._autorestapi.get_value("package-version"),
|
|
305
|
+
"client-side-validation": self._autorestapi.get_boolean_value(
|
|
306
|
+
"client-side-validation"
|
|
307
|
+
),
|
|
308
|
+
"tracing": self._autorestapi.get_boolean_value("trace"),
|
|
309
|
+
"multiapi": self._autorestapi.get_boolean_value("multiapi", False),
|
|
310
|
+
"polymorphic-examples": self._autorestapi.get_value("polymorphic-examples"),
|
|
311
|
+
"models-mode": self._autorestapi.get_value("models-mode"),
|
|
312
|
+
"builders-visibility": self._autorestapi.get_value("builders-visibility"),
|
|
313
|
+
"show-send-request": self._autorestapi.get_boolean_value(
|
|
314
|
+
"show-send-request"
|
|
315
|
+
),
|
|
316
|
+
"only-path-and-body-params-positional": self._autorestapi.get_boolean_value(
|
|
317
|
+
"only-path-and-body-params-positional"
|
|
318
|
+
),
|
|
319
|
+
"combine-operation-files": self._autorestapi.get_boolean_value(
|
|
320
|
+
"combine-operation-files"
|
|
321
|
+
),
|
|
322
|
+
"package-mode": self._autorestapi.get_value("package-mode"),
|
|
323
|
+
"package-pprint-name": self._autorestapi.get_value("package-pprint-name"),
|
|
324
|
+
"package-configuration": self._autorestapi.get_value(
|
|
325
|
+
"package-configuration"
|
|
326
|
+
),
|
|
327
|
+
"default-optional-constants-to-none": self._autorestapi.get_boolean_value(
|
|
328
|
+
"default-optional-constants-to-none"
|
|
329
|
+
),
|
|
330
|
+
}
|
|
331
|
+
return {k: v for k, v in options.items() if v is not None}
|
|
332
|
+
|
|
333
|
+
def get_yaml(self) -> Dict[str, Any]:
|
|
277
334
|
inputs = self._autorestapi.list_inputs()
|
|
278
335
|
_LOGGER.debug("Possible Inputs: %s", inputs)
|
|
279
336
|
if "code-model-v4-no-tags.yaml" not in inputs:
|
|
@@ -291,19 +348,10 @@ class CodeGenerator(Plugin):
|
|
|
291
348
|
file_content = self._autorestapi.read_file("code-model-v4-no-tags.yaml")
|
|
292
349
|
|
|
293
350
|
# Parse the received YAML
|
|
294
|
-
|
|
351
|
+
return yaml.safe_load(file_content)
|
|
295
352
|
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
if options["azure_arm"]:
|
|
299
|
-
self.remove_cloud_errors(yaml_data)
|
|
300
|
-
|
|
301
|
-
code_model = self._create_code_model(yaml_data=yaml_data, options=options)
|
|
302
|
-
|
|
303
|
-
serializer = JinjaSerializer(self._autorestapi, code_model)
|
|
304
|
-
serializer.serialize()
|
|
305
|
-
|
|
306
|
-
return True
|
|
353
|
+
def get_serializer(self, code_model: CodeModel): # type: ignore
|
|
354
|
+
return JinjaSerializerAutorest(self._autorestapi, code_model)
|
|
307
355
|
|
|
308
356
|
|
|
309
357
|
def main(yaml_model_file: str) -> None:
|
|
@@ -311,7 +359,7 @@ def main(yaml_model_file: str) -> None:
|
|
|
311
359
|
LocalAutorestAPI,
|
|
312
360
|
)
|
|
313
361
|
|
|
314
|
-
code_generator =
|
|
362
|
+
code_generator = CodeGeneratorAutorest(
|
|
315
363
|
autorestapi=LocalAutorestAPI(reachable_files=[yaml_model_file])
|
|
316
364
|
)
|
|
317
365
|
if not code_generator.process():
|
|
@@ -9,6 +9,7 @@ from jinja2 import PackageLoader, Environment, FileSystemLoader, StrictUndefined
|
|
|
9
9
|
from autorest.codegen.models.operation_group import OperationGroup
|
|
10
10
|
from autorest.codegen.models.request_builder import OverloadedRequestBuilder
|
|
11
11
|
|
|
12
|
+
from ... import ReaderAndWriter, ReaderAndWriterAutorest
|
|
12
13
|
from ...jsonrpc import AutorestAPI
|
|
13
14
|
from ..models import CodeModel, OperationGroup, RequestBuilder
|
|
14
15
|
from ..models import TokenCredentialType
|
|
@@ -38,9 +39,9 @@ _PACKAGE_FILES = [
|
|
|
38
39
|
_REGENERATE_FILES = {"setup.py", "MANIFEST.in"}
|
|
39
40
|
|
|
40
41
|
|
|
41
|
-
class JinjaSerializer:
|
|
42
|
-
def __init__(self,
|
|
43
|
-
|
|
42
|
+
class JinjaSerializer(ReaderAndWriter): # pylint: disable=abstract-method
|
|
43
|
+
def __init__(self, code_model: CodeModel, **kwargs: Any) -> None:
|
|
44
|
+
super().__init__(**kwargs)
|
|
44
45
|
self.code_model = code_model
|
|
45
46
|
|
|
46
47
|
@property
|
|
@@ -129,10 +130,10 @@ class JinjaSerializer:
|
|
|
129
130
|
)
|
|
130
131
|
if not self.code_model.options["models_mode"]:
|
|
131
132
|
# keep models file if users ended up just writing a models file
|
|
132
|
-
if self.
|
|
133
|
-
self.
|
|
133
|
+
if self.read_file(namespace_path / Path("models.py")):
|
|
134
|
+
self.write_file(
|
|
134
135
|
namespace_path / Path("models.py"),
|
|
135
|
-
self.
|
|
136
|
+
self.read_file(namespace_path / Path("models.py")),
|
|
136
137
|
)
|
|
137
138
|
|
|
138
139
|
if self.code_model.options["package_mode"]:
|
|
@@ -143,13 +144,10 @@ class JinjaSerializer:
|
|
|
143
144
|
for template_name in package_files:
|
|
144
145
|
file = template_name.replace(".jinja2", "")
|
|
145
146
|
output_name = out_path / file
|
|
146
|
-
if (
|
|
147
|
-
not self._autorestapi.read_file(output_name)
|
|
148
|
-
or file in _REGENERATE_FILES
|
|
149
|
-
):
|
|
147
|
+
if not self.read_file(output_name) or file in _REGENERATE_FILES:
|
|
150
148
|
template = env.get_template(template_name)
|
|
151
149
|
render_result = template.render(**kwargs)
|
|
152
|
-
self.
|
|
150
|
+
self.write_file(output_name, render_result)
|
|
153
151
|
|
|
154
152
|
def _prepare_params() -> Dict[Any, Any]:
|
|
155
153
|
package_parts = package_name.split("-")[:-1]
|
|
@@ -207,12 +205,10 @@ class JinjaSerializer:
|
|
|
207
205
|
_serialize_and_write_package_files_proc(**params)
|
|
208
206
|
|
|
209
207
|
def _keep_patch_file(self, path_file: Path, env: Environment):
|
|
210
|
-
if self.
|
|
211
|
-
self.
|
|
212
|
-
path_file, self._autorestapi.read_file(path_file)
|
|
213
|
-
)
|
|
208
|
+
if self.read_file(path_file):
|
|
209
|
+
self.write_file(path_file, self.read_file(path_file))
|
|
214
210
|
else:
|
|
215
|
-
self.
|
|
211
|
+
self.write_file(
|
|
216
212
|
path_file,
|
|
217
213
|
PatchSerializer(env=env, code_model=self.code_model).serialize(),
|
|
218
214
|
)
|
|
@@ -223,16 +219,16 @@ class JinjaSerializer:
|
|
|
223
219
|
# Write the models folder
|
|
224
220
|
models_path = namespace_path / Path("models")
|
|
225
221
|
if self.code_model.model_types:
|
|
226
|
-
self.
|
|
222
|
+
self.write_file(
|
|
227
223
|
models_path / Path(f"{self.code_model.models_filename}.py"),
|
|
228
224
|
ModelSerializer(code_model=self.code_model, env=env).serialize(),
|
|
229
225
|
)
|
|
230
226
|
if self.code_model.enums:
|
|
231
|
-
self.
|
|
227
|
+
self.write_file(
|
|
232
228
|
models_path / Path(f"{self.code_model.enums_filename}.py"),
|
|
233
229
|
EnumSerializer(code_model=self.code_model, env=env).serialize(),
|
|
234
230
|
)
|
|
235
|
-
self.
|
|
231
|
+
self.write_file(
|
|
236
232
|
models_path / Path("__init__.py"),
|
|
237
233
|
ModelInitSerializer(code_model=self.code_model, env=env).serialize(),
|
|
238
234
|
)
|
|
@@ -253,7 +249,7 @@ class JinjaSerializer:
|
|
|
253
249
|
env, rest_path, request_builders
|
|
254
250
|
)
|
|
255
251
|
if not "" in group_names:
|
|
256
|
-
self.
|
|
252
|
+
self.write_file(
|
|
257
253
|
rest_path / Path("__init__.py"),
|
|
258
254
|
self.code_model.options["license_header"],
|
|
259
255
|
)
|
|
@@ -267,7 +263,7 @@ class JinjaSerializer:
|
|
|
267
263
|
group_name = request_builders[0].group_name
|
|
268
264
|
output_path = rest_path / Path(group_name) if group_name else rest_path
|
|
269
265
|
# write generic request builders file
|
|
270
|
-
self.
|
|
266
|
+
self.write_file(
|
|
271
267
|
output_path / Path("_request_builders.py"),
|
|
272
268
|
RequestBuildersSerializer(
|
|
273
269
|
code_model=self.code_model,
|
|
@@ -277,7 +273,7 @@ class JinjaSerializer:
|
|
|
277
273
|
)
|
|
278
274
|
|
|
279
275
|
# write rest init file
|
|
280
|
-
self.
|
|
276
|
+
self.write_file(
|
|
281
277
|
output_path / Path("__init__.py"),
|
|
282
278
|
RequestBuildersSerializer(
|
|
283
279
|
code_model=self.code_model,
|
|
@@ -300,7 +296,7 @@ class JinjaSerializer:
|
|
|
300
296
|
async_mode=False,
|
|
301
297
|
operation_group=operation_group,
|
|
302
298
|
)
|
|
303
|
-
self.
|
|
299
|
+
self.write_file(
|
|
304
300
|
namespace_path
|
|
305
301
|
/ Path(self.code_model.operations_folder_name)
|
|
306
302
|
/ Path(f"{filename}.py"),
|
|
@@ -315,7 +311,7 @@ class JinjaSerializer:
|
|
|
315
311
|
async_mode=True,
|
|
316
312
|
operation_group=operation_group,
|
|
317
313
|
)
|
|
318
|
-
self.
|
|
314
|
+
self.write_file(
|
|
319
315
|
(
|
|
320
316
|
namespace_path
|
|
321
317
|
/ Path("aio")
|
|
@@ -332,7 +328,7 @@ class JinjaSerializer:
|
|
|
332
328
|
operations_init_serializer = OperationsInitSerializer(
|
|
333
329
|
code_model=self.code_model, env=env, async_mode=False
|
|
334
330
|
)
|
|
335
|
-
self.
|
|
331
|
+
self.write_file(
|
|
336
332
|
namespace_path
|
|
337
333
|
/ Path(self.code_model.operations_folder_name)
|
|
338
334
|
/ Path("__init__.py"),
|
|
@@ -344,7 +340,7 @@ class JinjaSerializer:
|
|
|
344
340
|
operations_async_init_serializer = OperationsInitSerializer(
|
|
345
341
|
code_model=self.code_model, env=env, async_mode=True
|
|
346
342
|
)
|
|
347
|
-
self.
|
|
343
|
+
self.write_file(
|
|
348
344
|
namespace_path
|
|
349
345
|
/ Path("aio")
|
|
350
346
|
/ Path(self.code_model.operations_folder_name)
|
|
@@ -369,12 +365,10 @@ class JinjaSerializer:
|
|
|
369
365
|
self, namespace_path: Path, general_serializer: GeneralSerializer
|
|
370
366
|
):
|
|
371
367
|
def _read_version_file(original_version_file_name: str) -> str:
|
|
372
|
-
return self.
|
|
373
|
-
namespace_path / original_version_file_name
|
|
374
|
-
)
|
|
368
|
+
return self.read_file(namespace_path / original_version_file_name)
|
|
375
369
|
|
|
376
370
|
def _write_version_file(original_version_file_name: str) -> None:
|
|
377
|
-
self.
|
|
371
|
+
self.write_file(
|
|
378
372
|
namespace_path / Path("_version.py"),
|
|
379
373
|
_read_version_file(original_version_file_name),
|
|
380
374
|
)
|
|
@@ -385,7 +379,7 @@ class JinjaSerializer:
|
|
|
385
379
|
elif keep_version_file and _read_version_file("version.py"):
|
|
386
380
|
_write_version_file(original_version_file_name="version.py")
|
|
387
381
|
elif self.code_model.options["package_version"]:
|
|
388
|
-
self.
|
|
382
|
+
self.write_file(
|
|
389
383
|
namespace_path / Path("_version.py"),
|
|
390
384
|
general_serializer.serialize_version_file(),
|
|
391
385
|
)
|
|
@@ -397,14 +391,14 @@ class JinjaSerializer:
|
|
|
397
391
|
code_model=self.code_model, env=env, async_mode=False
|
|
398
392
|
)
|
|
399
393
|
|
|
400
|
-
self.
|
|
394
|
+
self.write_file(
|
|
401
395
|
namespace_path / Path("__init__.py"),
|
|
402
396
|
general_serializer.serialize_init_file(),
|
|
403
397
|
)
|
|
404
398
|
p = namespace_path.parent
|
|
405
399
|
while p != Path("."):
|
|
406
400
|
# write pkgutil init file
|
|
407
|
-
self.
|
|
401
|
+
self.write_file(
|
|
408
402
|
p / Path("__init__.py"),
|
|
409
403
|
general_serializer.serialize_pkgutil_init_file(),
|
|
410
404
|
)
|
|
@@ -412,13 +406,13 @@ class JinjaSerializer:
|
|
|
412
406
|
|
|
413
407
|
# Write the service client
|
|
414
408
|
if self.code_model.request_builders:
|
|
415
|
-
self.
|
|
409
|
+
self.write_file(
|
|
416
410
|
namespace_path / Path(f"{self.code_model.client.filename}.py"),
|
|
417
411
|
general_serializer.serialize_service_client_file(),
|
|
418
412
|
)
|
|
419
413
|
|
|
420
414
|
if self.code_model.need_vendored_code(async_mode=False):
|
|
421
|
-
self.
|
|
415
|
+
self.write_file(
|
|
422
416
|
namespace_path / Path("_vendor.py"),
|
|
423
417
|
general_serializer.serialize_vendor_file(),
|
|
424
418
|
)
|
|
@@ -426,31 +420,27 @@ class JinjaSerializer:
|
|
|
426
420
|
self._serialize_and_write_version_file(namespace_path, general_serializer)
|
|
427
421
|
|
|
428
422
|
# write the empty py.typed file
|
|
429
|
-
self.
|
|
430
|
-
namespace_path / Path("py.typed"), "# Marker file for PEP 561."
|
|
431
|
-
)
|
|
423
|
+
self.write_file(namespace_path / Path("py.typed"), "# Marker file for PEP 561.")
|
|
432
424
|
|
|
433
425
|
if (
|
|
434
426
|
not self.code_model.options["client_side_validation"]
|
|
435
427
|
and not self.code_model.options["multiapi"]
|
|
436
428
|
):
|
|
437
|
-
self.
|
|
429
|
+
self.write_file(
|
|
438
430
|
namespace_path / Path("_serialization.py"),
|
|
439
431
|
general_serializer.serialize_serialization_file(),
|
|
440
432
|
)
|
|
441
433
|
|
|
442
434
|
# Write the config file
|
|
443
435
|
if self.code_model.request_builders:
|
|
444
|
-
self.
|
|
436
|
+
self.write_file(
|
|
445
437
|
namespace_path / Path("_configuration.py"),
|
|
446
438
|
general_serializer.serialize_config_file(),
|
|
447
439
|
)
|
|
448
440
|
|
|
449
441
|
# Write the setup file
|
|
450
442
|
if self.code_model.options["basic_setup_py"]:
|
|
451
|
-
self.
|
|
452
|
-
Path("setup.py"), general_serializer.serialize_setup_file()
|
|
453
|
-
)
|
|
443
|
+
self.write_file(Path("setup.py"), general_serializer.serialize_setup_file())
|
|
454
444
|
|
|
455
445
|
def _serialize_and_write_aio_top_level_folder(
|
|
456
446
|
self, env: Environment, namespace_path: Path
|
|
@@ -462,24 +452,24 @@ class JinjaSerializer:
|
|
|
462
452
|
aio_path = namespace_path / Path("aio")
|
|
463
453
|
|
|
464
454
|
# Write the __init__ file
|
|
465
|
-
self.
|
|
455
|
+
self.write_file(
|
|
466
456
|
aio_path / Path("__init__.py"), aio_general_serializer.serialize_init_file()
|
|
467
457
|
)
|
|
468
458
|
|
|
469
459
|
# Write the service client
|
|
470
460
|
if self.code_model.request_builders:
|
|
471
|
-
self.
|
|
461
|
+
self.write_file(
|
|
472
462
|
aio_path / Path(f"{self.code_model.client.filename}.py"),
|
|
473
463
|
aio_general_serializer.serialize_service_client_file(),
|
|
474
464
|
)
|
|
475
465
|
|
|
476
466
|
# Write the config file
|
|
477
|
-
self.
|
|
467
|
+
self.write_file(
|
|
478
468
|
aio_path / Path("_configuration.py"),
|
|
479
469
|
aio_general_serializer.serialize_config_file(),
|
|
480
470
|
)
|
|
481
471
|
if self.code_model.need_vendored_code(async_mode=True):
|
|
482
|
-
self.
|
|
472
|
+
self.write_file(
|
|
483
473
|
aio_path / Path("_vendor.py"),
|
|
484
474
|
aio_general_serializer.serialize_vendor_file(),
|
|
485
475
|
)
|
|
@@ -488,6 +478,11 @@ class JinjaSerializer:
|
|
|
488
478
|
self, env: Environment, namespace_path: Path
|
|
489
479
|
) -> None:
|
|
490
480
|
metadata_serializer = MetadataSerializer(self.code_model, env)
|
|
491
|
-
self.
|
|
481
|
+
self.write_file(
|
|
492
482
|
namespace_path / Path("_metadata.json"), metadata_serializer.serialize()
|
|
493
483
|
)
|
|
484
|
+
|
|
485
|
+
|
|
486
|
+
class JinjaSerializerAutorest(JinjaSerializer, ReaderAndWriterAutorest):
|
|
487
|
+
def __init__(self, autorestapi: AutorestAPI, code_model: CodeModel) -> None:
|
|
488
|
+
super().__init__(autorestapi=autorestapi, code_model=code_model)
|
|
@@ -16,6 +16,11 @@ class ClientSerializer:
|
|
|
16
16
|
self.parameter_serializer = ParameterSerializer()
|
|
17
17
|
|
|
18
18
|
def _init_signature(self, async_mode: bool) -> str:
|
|
19
|
+
pylint_disable = ""
|
|
20
|
+
if not self.code_model.client.parameters.credential:
|
|
21
|
+
pylint_disable = (
|
|
22
|
+
" # pylint: disable=missing-client-constructor-parameter-credential"
|
|
23
|
+
)
|
|
19
24
|
return self.parameter_serializer.serialize_method(
|
|
20
25
|
function_def="def",
|
|
21
26
|
method_name="__init__",
|
|
@@ -23,6 +28,7 @@ class ClientSerializer:
|
|
|
23
28
|
method_param_signatures=self.code_model.client.parameters.method_signature(
|
|
24
29
|
async_mode
|
|
25
30
|
),
|
|
31
|
+
pylint_disable=pylint_disable,
|
|
26
32
|
)
|
|
27
33
|
|
|
28
34
|
def init_signature_and_response_type_annotation(self, async_mode: bool) -> str:
|
|
@@ -43,24 +43,24 @@ def Process(plugin_name: str, session_id: str) -> bool:
|
|
|
43
43
|
session_id,
|
|
44
44
|
)
|
|
45
45
|
if plugin_name == "m2r":
|
|
46
|
-
from ..m2r import
|
|
46
|
+
from ..m2r import M2RAutorest as PluginToLoad
|
|
47
47
|
elif plugin_name == "preprocess":
|
|
48
|
-
from ..preprocess import
|
|
48
|
+
from ..preprocess import PreProcessPluginAutorest as PluginToLoad # type: ignore
|
|
49
49
|
elif plugin_name == "m4reformatter":
|
|
50
50
|
from ..m4reformatter import M4Reformatter as PluginToLoad # type: ignore
|
|
51
51
|
elif plugin_name == "codegen":
|
|
52
|
-
from ..codegen import
|
|
52
|
+
from ..codegen import CodeGeneratorAutorest as PluginToLoad # type: ignore
|
|
53
53
|
elif plugin_name == "postprocess":
|
|
54
|
-
from ..postprocess import
|
|
54
|
+
from ..postprocess import PostProcessPluginAutorest as PluginToLoad # type: ignore
|
|
55
55
|
elif plugin_name == "black":
|
|
56
|
-
from ..black import
|
|
56
|
+
from ..black import BlackScriptPluginAutorest as PluginToLoad # type: ignore
|
|
57
57
|
elif plugin_name == "multiapiscript":
|
|
58
|
-
from ..multiapi import
|
|
58
|
+
from ..multiapi import MultiApiScriptPluginAutorest as PluginToLoad # type: ignore
|
|
59
59
|
else:
|
|
60
60
|
_LOGGER.fatal("Unknown plugin name %s", plugin_name)
|
|
61
61
|
raise RuntimeError(f"Unknown plugin name {plugin_name}")
|
|
62
62
|
|
|
63
|
-
plugin = PluginToLoad(stdstream_connection)
|
|
63
|
+
plugin = PluginToLoad(autorestapi=stdstream_connection)
|
|
64
64
|
|
|
65
65
|
try:
|
|
66
66
|
_LOGGER.debug("Starting plugin %s", PluginToLoad.__name__)
|
package/autorest/m2r/__init__.py
CHANGED
|
@@ -10,7 +10,7 @@ from typing import Any, Dict, Set
|
|
|
10
10
|
|
|
11
11
|
import m2r
|
|
12
12
|
|
|
13
|
-
from .. import YamlUpdatePlugin
|
|
13
|
+
from .. import YamlUpdatePluginAutorest, YamlUpdatePlugin
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
_LOGGER = logging.getLogger(__name__)
|
|
@@ -26,7 +26,7 @@ class AutorestRender(m2r.RestRenderer):
|
|
|
26
26
|
return f":code:`{html}`"
|
|
27
27
|
|
|
28
28
|
|
|
29
|
-
class M2R(YamlUpdatePlugin):
|
|
29
|
+
class M2R(YamlUpdatePlugin): # pylint: disable=abstract-method
|
|
30
30
|
"""A plugin to convert any description and summary from MD to RST."""
|
|
31
31
|
|
|
32
32
|
def update_yaml(self, yaml_data: Dict[str, Any]) -> None:
|
|
@@ -58,3 +58,8 @@ class M2R(YamlUpdatePlugin):
|
|
|
58
58
|
return m2r.convert(string_to_convert, renderer=AutorestRender()).strip()
|
|
59
59
|
except Exception: # pylint: disable=broad-except
|
|
60
60
|
return string_to_convert
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
class M2RAutorest(YamlUpdatePluginAutorest, M2R):
|
|
64
|
+
def get_options(self) -> Dict[str, Any]:
|
|
65
|
+
return {}
|
|
@@ -11,7 +11,7 @@ import copy
|
|
|
11
11
|
import logging
|
|
12
12
|
from typing import Callable, Dict, Any, Iterable, List, Optional, Set
|
|
13
13
|
|
|
14
|
-
from .. import
|
|
14
|
+
from .. import YamlUpdatePluginAutorest
|
|
15
15
|
|
|
16
16
|
JSON_REGEXP = re.compile(r"^(application|text)/(.+\+)?json$")
|
|
17
17
|
ORIGINAL_ID_TO_UPDATED_TYPE: Dict[int, Dict[str, Any]] = {}
|
|
@@ -431,7 +431,9 @@ def update_client_url(yaml_data: Dict[str, Any]) -> str:
|
|
|
431
431
|
]["uri"]
|
|
432
432
|
|
|
433
433
|
|
|
434
|
-
class M4Reformatter(
|
|
434
|
+
class M4Reformatter(
|
|
435
|
+
YamlUpdatePluginAutorest
|
|
436
|
+
): # pylint: disable=too-many-public-methods
|
|
435
437
|
"""Add Python naming information."""
|
|
436
438
|
|
|
437
439
|
@property
|
|
@@ -11,41 +11,62 @@ import shutil
|
|
|
11
11
|
from collections import defaultdict
|
|
12
12
|
from pathlib import Path
|
|
13
13
|
from typing import Dict, List, Optional, cast, Any
|
|
14
|
-
|
|
14
|
+
|
|
15
|
+
from .serializers import MultiAPISerializer, MultiAPISerializerAutorest
|
|
15
16
|
from .models import CodeModel
|
|
16
17
|
from .utils import _get_default_api_version_from_list
|
|
17
|
-
from ..jsonrpc import AutorestAPI
|
|
18
18
|
|
|
19
|
-
from .. import Plugin
|
|
19
|
+
from .. import Plugin, PluginAutorest, ReaderAndWriter, ReaderAndWriterAutorest
|
|
20
20
|
|
|
21
21
|
_LOGGER = logging.getLogger(__name__)
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
class MultiApiScriptPlugin(Plugin):
|
|
24
|
+
class MultiApiScriptPlugin(Plugin): # pylint: disable=abstract-method
|
|
25
25
|
def process(self) -> bool:
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
input_package_name,
|
|
32
|
-
output_folder,
|
|
33
|
-
self.
|
|
34
|
-
no_async,
|
|
35
|
-
user_specified_default_api,
|
|
26
|
+
return self.generator.process()
|
|
27
|
+
|
|
28
|
+
@property
|
|
29
|
+
def generator(self) -> "MultiAPI":
|
|
30
|
+
return MultiAPI(
|
|
31
|
+
input_package_name=self.options.get("package-name"),
|
|
32
|
+
output_folder=self.options["output-folder"],
|
|
33
|
+
user_specified_default_api=self.options.get("default-api"),
|
|
34
|
+
no_async=self.options.get("no-async", False),
|
|
36
35
|
)
|
|
37
|
-
return generator.process()
|
|
38
36
|
|
|
39
37
|
|
|
40
|
-
class
|
|
38
|
+
class MultiApiScriptPluginAutorest(MultiApiScriptPlugin, PluginAutorest):
|
|
39
|
+
@property
|
|
40
|
+
def generator(self) -> "MultiAPI":
|
|
41
|
+
return MultiAPIAutorest(
|
|
42
|
+
autorestapi=self._autorestapi,
|
|
43
|
+
input_package_name=self.options.get("package-name"),
|
|
44
|
+
output_folder=self.options["output-folder"],
|
|
45
|
+
user_specified_default_api=self.options.get("default-api"),
|
|
46
|
+
no_async=self.options.get("no-async", False),
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
def get_options(self) -> Dict[str, Any]:
|
|
50
|
+
options = {
|
|
51
|
+
"package-name": self._autorestapi.get_value("package-name"),
|
|
52
|
+
"output-folder": self._autorestapi.get_value("output-folder"),
|
|
53
|
+
"default-api": self._autorestapi.get_value("default-api"),
|
|
54
|
+
"no-async": self._autorestapi.get_value("no-async"),
|
|
55
|
+
}
|
|
56
|
+
return {k: v for k, v in options.items() if v is not None}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class MultiAPI(ReaderAndWriter): # pylint: disable=abstract-method
|
|
41
60
|
def __init__(
|
|
42
61
|
self,
|
|
43
|
-
|
|
62
|
+
*,
|
|
63
|
+
input_package_name: Optional[str] = None,
|
|
44
64
|
output_folder: str,
|
|
45
|
-
autorestapi: AutorestAPI,
|
|
46
65
|
no_async: Optional[bool] = False,
|
|
47
66
|
user_specified_default_api: Optional[str] = None,
|
|
67
|
+
**kwargs: Any,
|
|
48
68
|
) -> None:
|
|
69
|
+
super().__init__(**kwargs)
|
|
49
70
|
if input_package_name is None:
|
|
50
71
|
raise ValueError(
|
|
51
72
|
"package-name is required, either provide it as args or check your readme configuration"
|
|
@@ -57,7 +78,6 @@ class MultiAPI:
|
|
|
57
78
|
_LOGGER.debug("Received output-folder %s", output_folder)
|
|
58
79
|
self.output_package_name: str = ""
|
|
59
80
|
self.no_async = no_async
|
|
60
|
-
self._autorestapi = autorestapi
|
|
61
81
|
self.user_specified_default_api = user_specified_default_api
|
|
62
82
|
|
|
63
83
|
@property
|
|
@@ -77,9 +97,7 @@ class MultiAPI:
|
|
|
77
97
|
if self.default_api_version.replace("-", "_") == path_to_version.stem:
|
|
78
98
|
path_to_default_version = path_to_version
|
|
79
99
|
break
|
|
80
|
-
return json.loads(
|
|
81
|
-
self._autorestapi.read_file(path_to_default_version / "_metadata.json")
|
|
82
|
-
)
|
|
100
|
+
return json.loads(self.read_file(path_to_default_version / "_metadata.json"))
|
|
83
101
|
|
|
84
102
|
@property
|
|
85
103
|
def module_name(self) -> str:
|
|
@@ -120,9 +138,7 @@ class MultiAPI:
|
|
|
120
138
|
@property
|
|
121
139
|
def version_path_to_metadata(self) -> Dict[Path, Dict[str, Any]]:
|
|
122
140
|
return {
|
|
123
|
-
version_path: json.loads(
|
|
124
|
-
self._autorestapi.read_file(version_path / "_metadata.json")
|
|
125
|
-
)
|
|
141
|
+
version_path: json.loads(self.read_file(version_path / "_metadata.json"))
|
|
126
142
|
for version_path in self.paths_to_versions
|
|
127
143
|
}
|
|
128
144
|
|
|
@@ -130,9 +146,7 @@ class MultiAPI:
|
|
|
130
146
|
def mod_to_api_version(self) -> Dict[str, str]:
|
|
131
147
|
mod_to_api_version: Dict[str, str] = defaultdict(str)
|
|
132
148
|
for version_path in self.paths_to_versions:
|
|
133
|
-
metadata_json = json.loads(
|
|
134
|
-
self._autorestapi.read_file(version_path / "_metadata.json")
|
|
135
|
-
)
|
|
149
|
+
metadata_json = json.loads(self.read_file(version_path / "_metadata.json"))
|
|
136
150
|
version = metadata_json["chosen_version"]
|
|
137
151
|
total_api_version_list = metadata_json["total_api_version_list"]
|
|
138
152
|
if not version:
|
|
@@ -145,6 +159,10 @@ class MultiAPI:
|
|
|
145
159
|
mod_to_api_version[version_path.name] = version
|
|
146
160
|
return mod_to_api_version
|
|
147
161
|
|
|
162
|
+
@property
|
|
163
|
+
def serializer(self) -> MultiAPISerializer:
|
|
164
|
+
return MultiAPISerializer()
|
|
165
|
+
|
|
148
166
|
def process(self) -> bool:
|
|
149
167
|
_LOGGER.info("Generating multiapi client")
|
|
150
168
|
|
|
@@ -163,8 +181,17 @@ class MultiAPI:
|
|
|
163
181
|
shutil.rmtree(str(self.output_folder / "operations"), ignore_errors=True)
|
|
164
182
|
shutil.rmtree(str(self.output_folder / "models"), ignore_errors=True)
|
|
165
183
|
|
|
166
|
-
multiapi_serializer =
|
|
184
|
+
multiapi_serializer = self.serializer
|
|
167
185
|
multiapi_serializer.serialize(code_model, self.no_async)
|
|
168
186
|
|
|
169
187
|
_LOGGER.info("Done!")
|
|
170
188
|
return True
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
class MultiAPIAutorest(MultiAPI, ReaderAndWriterAutorest):
|
|
192
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
193
|
+
super().__init__(**kwargs)
|
|
194
|
+
|
|
195
|
+
@property
|
|
196
|
+
def serializer(self) -> MultiAPISerializer:
|
|
197
|
+
return MultiAPISerializerAutorest(self._autorestapi)
|
|
@@ -11,6 +11,7 @@ from .import_serializer import FileImportSerializer
|
|
|
11
11
|
|
|
12
12
|
from ...jsonrpc import AutorestAPI
|
|
13
13
|
from ..models import CodeModel
|
|
14
|
+
from ... import ReaderAndWriter, ReaderAndWriterAutorest
|
|
14
15
|
|
|
15
16
|
__all__ = [
|
|
16
17
|
"MultiAPISerializer",
|
|
@@ -32,9 +33,9 @@ def _get_file_path(filename: str, async_mode: bool) -> Path:
|
|
|
32
33
|
return Path(filename)
|
|
33
34
|
|
|
34
35
|
|
|
35
|
-
class MultiAPISerializer(
|
|
36
|
-
def __init__(self,
|
|
37
|
-
|
|
36
|
+
class MultiAPISerializer(ReaderAndWriter): # pylint: disable=abstract-method
|
|
37
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
38
|
+
super().__init__(**kwargs)
|
|
38
39
|
self.env = Environment(
|
|
39
40
|
loader=PackageLoader("autorest.multiapi", "templates"),
|
|
40
41
|
keep_trailing_newline=True,
|
|
@@ -52,20 +53,20 @@ class MultiAPISerializer(object):
|
|
|
52
53
|
)
|
|
53
54
|
|
|
54
55
|
# serialize init file
|
|
55
|
-
self.
|
|
56
|
+
self.write_file(
|
|
56
57
|
_get_file_path("__init__", async_mode), _render_template("init")
|
|
57
58
|
)
|
|
58
59
|
|
|
59
60
|
# serialize service client file
|
|
60
61
|
imports = FileImportSerializer(code_model.client.imports(async_mode))
|
|
61
|
-
self.
|
|
62
|
+
self.write_file(
|
|
62
63
|
_get_file_path(code_model.client.filename, async_mode),
|
|
63
64
|
_render_template("client", imports=imports),
|
|
64
65
|
)
|
|
65
66
|
|
|
66
67
|
# serialize config file
|
|
67
68
|
imports = FileImportSerializer(code_model.config.imports(async_mode))
|
|
68
|
-
self.
|
|
69
|
+
self.write_file(
|
|
69
70
|
_get_file_path("_configuration", async_mode),
|
|
70
71
|
_render_template("config", imports=imports),
|
|
71
72
|
)
|
|
@@ -75,26 +76,22 @@ class MultiAPISerializer(object):
|
|
|
75
76
|
imports = FileImportSerializer(
|
|
76
77
|
code_model.operation_mixin_group.imports(async_mode)
|
|
77
78
|
)
|
|
78
|
-
self.
|
|
79
|
+
self.write_file(
|
|
79
80
|
_get_file_path("_operations_mixin", async_mode),
|
|
80
81
|
_render_template("operations_mixin", imports=imports),
|
|
81
82
|
)
|
|
82
83
|
|
|
83
84
|
# serialize models
|
|
84
|
-
self.
|
|
85
|
+
self.write_file(Path("models.py"), _render_template("models"))
|
|
85
86
|
|
|
86
87
|
def _serialize_version_file(self) -> None:
|
|
87
|
-
if self.
|
|
88
|
-
self.
|
|
89
|
-
|
|
90
|
-
)
|
|
91
|
-
elif self._autorestapi.read_file("version.py"):
|
|
92
|
-
self._autorestapi.write_file(
|
|
93
|
-
"_version.py", self._autorestapi.read_file("version.py")
|
|
94
|
-
)
|
|
88
|
+
if self.read_file("_version.py"):
|
|
89
|
+
self.write_file("_version.py", self.read_file("_version.py"))
|
|
90
|
+
elif self.read_file("version.py"):
|
|
91
|
+
self.write_file("_version.py", self.read_file("version.py"))
|
|
95
92
|
else:
|
|
96
93
|
template = self.env.get_template("multiapi_version.py.jinja2")
|
|
97
|
-
self.
|
|
94
|
+
self.write_file(Path("_version.py"), template.render())
|
|
98
95
|
|
|
99
96
|
def serialize(self, code_model: CodeModel, no_async: Optional[bool]) -> None:
|
|
100
97
|
self._serialize_helper(code_model, async_mode=False)
|
|
@@ -104,12 +101,10 @@ class MultiAPISerializer(object):
|
|
|
104
101
|
self._serialize_version_file()
|
|
105
102
|
|
|
106
103
|
# don't erase patch file
|
|
107
|
-
if self.
|
|
108
|
-
self.
|
|
109
|
-
"_patch.py", self._autorestapi.read_file("_patch.py")
|
|
110
|
-
)
|
|
104
|
+
if self.read_file("_patch.py"):
|
|
105
|
+
self.write_file("_patch.py", self.read_file("_patch.py"))
|
|
111
106
|
|
|
112
|
-
self.
|
|
107
|
+
self.write_file(Path("py.typed"), "# Marker file for PEP 561.")
|
|
113
108
|
|
|
114
109
|
if not code_model.client.client_side_validation:
|
|
115
110
|
codegen_env = Environment(
|
|
@@ -120,7 +115,12 @@ class MultiAPISerializer(object):
|
|
|
120
115
|
trim_blocks=True,
|
|
121
116
|
lstrip_blocks=True,
|
|
122
117
|
)
|
|
123
|
-
self.
|
|
118
|
+
self.write_file(
|
|
124
119
|
Path("_serialization.py"),
|
|
125
120
|
codegen_env.get_template("serialization.py.jinja2").render(),
|
|
126
121
|
)
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class MultiAPISerializerAutorest(MultiAPISerializer, ReaderAndWriterAutorest):
|
|
125
|
+
def __init__(self, autorestapi: AutorestAPI) -> None:
|
|
126
|
+
super().__init__(autorestapi=autorestapi)
|
|
@@ -8,19 +8,20 @@ from pathlib import Path
|
|
|
8
8
|
from jinja2 import Environment, PackageLoader
|
|
9
9
|
|
|
10
10
|
from ...jsonrpc import AutorestAPI
|
|
11
|
+
from ... import ReaderAndWriter, ReaderAndWriterAutorest
|
|
11
12
|
|
|
12
13
|
|
|
13
|
-
class MultiAPISerializer:
|
|
14
|
+
class MultiAPISerializer(ReaderAndWriter): # pylint: disable=abstract-method
|
|
14
15
|
def __init__(
|
|
15
16
|
self,
|
|
16
17
|
conf: Dict[str, Any],
|
|
17
18
|
async_mode: bool,
|
|
18
|
-
autorestapi: AutorestAPI,
|
|
19
19
|
service_client_filename: str,
|
|
20
|
+
**kwargs: Any
|
|
20
21
|
):
|
|
22
|
+
super().__init__(**kwargs)
|
|
21
23
|
self.conf = conf
|
|
22
24
|
self.async_mode = async_mode
|
|
23
|
-
self._autorestapi = autorestapi
|
|
24
25
|
self.service_client_filename = service_client_filename
|
|
25
26
|
self.env = Environment(
|
|
26
27
|
loader=PackageLoader("autorest.multiapi", "templates"),
|
|
@@ -37,53 +38,43 @@ class MultiAPISerializer:
|
|
|
37
38
|
return Path(filename)
|
|
38
39
|
|
|
39
40
|
def serialize(self):
|
|
40
|
-
self.
|
|
41
|
+
self.write_file(
|
|
41
42
|
self._get_file_path("__init__.py"), self.serialize_multiapi_init()
|
|
42
43
|
)
|
|
43
44
|
|
|
44
45
|
service_client_filename_with_py_extension = self.service_client_filename + ".py"
|
|
45
|
-
self.
|
|
46
|
+
self.write_file(
|
|
46
47
|
self._get_file_path(service_client_filename_with_py_extension),
|
|
47
48
|
self.serialize_multiapi_client(),
|
|
48
49
|
)
|
|
49
50
|
|
|
50
51
|
configuration_filename = "_configuration.py"
|
|
51
|
-
self.
|
|
52
|
+
self.write_file(
|
|
52
53
|
self._get_file_path(configuration_filename),
|
|
53
54
|
self.serialize_multiapi_config(),
|
|
54
55
|
)
|
|
55
56
|
|
|
56
57
|
operation_mixins_filename = "_operations_mixin.py"
|
|
57
58
|
if self.conf["mixin_operations"]:
|
|
58
|
-
self.
|
|
59
|
+
self.write_file(
|
|
59
60
|
self._get_file_path(operation_mixins_filename),
|
|
60
61
|
self.serialize_multiapi_operation_mixins(),
|
|
61
62
|
)
|
|
62
63
|
|
|
63
|
-
if self.
|
|
64
|
-
self.
|
|
65
|
-
|
|
66
|
-
)
|
|
67
|
-
elif self._autorestapi.read_file("version.py"):
|
|
68
|
-
self._autorestapi.write_file(
|
|
69
|
-
"_version.py", self._autorestapi.read_file("version.py")
|
|
70
|
-
)
|
|
64
|
+
if self.read_file("_version.py"):
|
|
65
|
+
self.write_file("_version.py", self.read_file("_version.py"))
|
|
66
|
+
elif self.read_file("version.py"):
|
|
67
|
+
self.write_file("_version.py", self.read_file("version.py"))
|
|
71
68
|
else:
|
|
72
|
-
self.
|
|
73
|
-
Path("_version.py"), self.serialize_multiapi_version()
|
|
74
|
-
)
|
|
69
|
+
self.write_file(Path("_version.py"), self.serialize_multiapi_version())
|
|
75
70
|
|
|
76
71
|
# don't erase patch file
|
|
77
|
-
if self.
|
|
78
|
-
self.
|
|
79
|
-
"_patch.py", self._autorestapi.read_file("_patch.py")
|
|
80
|
-
)
|
|
72
|
+
if self.read_file("_patch.py"):
|
|
73
|
+
self.write_file("_patch.py", self.read_file("_patch.py"))
|
|
81
74
|
|
|
82
|
-
self.
|
|
83
|
-
Path("models.py"), self.serialize_multiapi_models()
|
|
84
|
-
)
|
|
75
|
+
self.write_file(Path("models.py"), self.serialize_multiapi_models())
|
|
85
76
|
|
|
86
|
-
self.
|
|
77
|
+
self.write_file(Path("py.typed"), "# Marker file for PEP 561.")
|
|
87
78
|
|
|
88
79
|
def serialize_multiapi_init(self) -> str:
|
|
89
80
|
template = self.env.get_template("multiapi_init.py.jinja2")
|
|
@@ -112,3 +103,19 @@ class MultiAPISerializer:
|
|
|
112
103
|
def serialize_multiapi_operation_mixins(self) -> str:
|
|
113
104
|
template = self.env.get_template("multiapi_operations_mixin.py.jinja2")
|
|
114
105
|
return template.render(**self.conf, async_mode=self.async_mode)
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class MultiAPISerializerAutorest(MultiAPISerializer, ReaderAndWriterAutorest):
|
|
109
|
+
def __init__(
|
|
110
|
+
self,
|
|
111
|
+
autorestapi: AutorestAPI,
|
|
112
|
+
conf: Dict[str, Any],
|
|
113
|
+
async_mode: bool,
|
|
114
|
+
service_client_filename: str,
|
|
115
|
+
):
|
|
116
|
+
super().__init__(
|
|
117
|
+
autorestapi=autorestapi,
|
|
118
|
+
conf=conf,
|
|
119
|
+
async_mode=async_mode,
|
|
120
|
+
service_client_filename=service_client_filename,
|
|
121
|
+
)
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# Licensed under the MIT License. See License.txt in the project root for
|
|
4
4
|
# license information.
|
|
5
5
|
# --------------------------------------------------------------------------
|
|
6
|
-
from typing import Tuple
|
|
6
|
+
from typing import Tuple, Any, Dict
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
import os
|
|
9
9
|
import shutil
|
|
@@ -11,7 +11,7 @@ from venv import EnvBuilder
|
|
|
11
11
|
import black
|
|
12
12
|
from .venvtools import ExtendedEnvBuilder, python_run
|
|
13
13
|
|
|
14
|
-
from .. import Plugin
|
|
14
|
+
from .. import Plugin, PluginAutorest
|
|
15
15
|
|
|
16
16
|
_BLACK_MODE = black.Mode()
|
|
17
17
|
_BLACK_MODE.line_length = 120
|
|
@@ -29,10 +29,10 @@ def format_file(file: Path, file_content: str) -> str:
|
|
|
29
29
|
return file_content
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
class PostProcessPlugin(Plugin):
|
|
33
|
-
def __init__(self,
|
|
34
|
-
super().__init__(
|
|
35
|
-
output_folder_uri = self.
|
|
32
|
+
class PostProcessPlugin(Plugin): # pylint: disable=abstract-method
|
|
33
|
+
def __init__(self, **kwargs: Any):
|
|
34
|
+
super().__init__(**kwargs)
|
|
35
|
+
output_folder_uri = self.options["outputFolderUri"]
|
|
36
36
|
if output_folder_uri.startswith("file:"):
|
|
37
37
|
output_folder_uri = output_folder_uri[5:]
|
|
38
38
|
if os.name == "nt" and output_folder_uri.startswith("///"):
|
|
@@ -65,9 +65,7 @@ class PostProcessPlugin(Plugin):
|
|
|
65
65
|
try:
|
|
66
66
|
init_file = next(d for d in dir.iterdir() if d.name == "__init__.py")
|
|
67
67
|
# we don't care about pkgutil inits, we skip over them
|
|
68
|
-
file_content = self.
|
|
69
|
-
init_file.relative_to(self.output_folder)
|
|
70
|
-
)
|
|
68
|
+
file_content = self.read_file(init_file.relative_to(self.output_folder))
|
|
71
69
|
if not "pkgutil" in file_content:
|
|
72
70
|
return dir, namespace
|
|
73
71
|
except StopIteration:
|
|
@@ -157,7 +155,7 @@ class PostProcessPlugin(Plugin):
|
|
|
157
155
|
k: None for k in customized_objects_str.split(",")
|
|
158
156
|
}.keys() # filter out duplicates
|
|
159
157
|
file = (folder_path / "__init__.py").relative_to(self.output_folder)
|
|
160
|
-
file_content = self.
|
|
158
|
+
file_content = self.read_file(file)
|
|
161
159
|
added_objs = []
|
|
162
160
|
for obj in customized_objects:
|
|
163
161
|
if f" import {obj}\n" in file_content:
|
|
@@ -199,4 +197,9 @@ class PostProcessPlugin(Plugin):
|
|
|
199
197
|
"__all__ = [", f"__all__ = [\n{added_objs_all}", 1
|
|
200
198
|
)
|
|
201
199
|
formatted_file = format_file(file, file_content)
|
|
202
|
-
self.
|
|
200
|
+
self.write_file(file, formatted_file)
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
class PostProcessPluginAutorest(PostProcessPlugin, PluginAutorest):
|
|
204
|
+
def get_options(self) -> Dict[str, Any]:
|
|
205
|
+
return {"outputFolderUri": self._autorestapi.get_value("outputFolderUri")}
|
|
@@ -9,7 +9,7 @@ from typing import Callable, Dict, Any, List, Optional
|
|
|
9
9
|
from .helpers import to_snake_case, pad_reserved_words, add_redefined_builtin_info
|
|
10
10
|
from .python_mappings import PadType
|
|
11
11
|
|
|
12
|
-
from .. import YamlUpdatePlugin
|
|
12
|
+
from .. import YamlUpdatePlugin, PluginAutorest
|
|
13
13
|
|
|
14
14
|
|
|
15
15
|
def _remove_paging_maxpagesize(yaml_data: Dict[str, Any]) -> None:
|
|
@@ -92,12 +92,12 @@ def update_paging_response(yaml_data: Dict[str, Any]) -> None:
|
|
|
92
92
|
)
|
|
93
93
|
|
|
94
94
|
|
|
95
|
-
class PreProcessPlugin(YamlUpdatePlugin):
|
|
95
|
+
class PreProcessPlugin(YamlUpdatePlugin): # pylint: disable=abstract-method
|
|
96
96
|
"""Add Python naming information."""
|
|
97
97
|
|
|
98
98
|
@property
|
|
99
99
|
def version_tolerant(self) -> bool:
|
|
100
|
-
return
|
|
100
|
+
return self.options.get("version-tolerant", True)
|
|
101
101
|
|
|
102
102
|
def get_operation_updater(
|
|
103
103
|
self, yaml_data: Dict[str, Any]
|
|
@@ -133,7 +133,7 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
133
133
|
response["discriminator"] = "operation"
|
|
134
134
|
|
|
135
135
|
def _update_lro_operation_helper(self, yaml_data: Dict[str, Any]) -> None:
|
|
136
|
-
azure_arm = self.
|
|
136
|
+
azure_arm = self.options.get("azure-arm", False)
|
|
137
137
|
for response in yaml_data.get("responses", []):
|
|
138
138
|
response["discriminator"] = "lro"
|
|
139
139
|
response["pollerSync"] = (
|
|
@@ -228,3 +228,12 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
228
228
|
update_client(yaml_data["client"])
|
|
229
229
|
update_types(yaml_data["types"])
|
|
230
230
|
self.update_operation_groups(yaml_data)
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
class PreProcessPluginAutorest(PluginAutorest, PreProcessPlugin):
|
|
234
|
+
def get_options(self) -> Dict[str, Any]:
|
|
235
|
+
options = {
|
|
236
|
+
"version-tolerant": self._autorestapi.get_boolean_value("version-tolerant"),
|
|
237
|
+
"azure-arm": self._autorestapi.get_boolean_value("azure-arm"),
|
|
238
|
+
}
|
|
239
|
+
return {k: v for k, v in options.items() if v is not None}
|