@autorest/python 6.0.0-rc.1 → 6.1.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 +60 -2
- package/README.md +21 -2
- package/autorest/__init__.py +80 -14
- package/autorest/_utils.py +56 -0
- package/autorest/black/__init__.py +27 -14
- package/autorest/codegen/__init__.py +131 -90
- package/autorest/codegen/_utils.py +14 -0
- package/autorest/codegen/models/__init__.py +10 -1
- package/autorest/codegen/models/model_type.py +12 -1
- package/autorest/codegen/models/paging_operation.py +15 -1
- package/autorest/codegen/serializers/__init__.py +58 -58
- package/autorest/codegen/serializers/builder_serializer.py +26 -5
- package/autorest/codegen/serializers/client_serializer.py +6 -0
- package/autorest/codegen/templates/README.md.jinja2 +3 -3
- package/autorest/codegen/templates/serialization.py.jinja2 +3 -3
- package/autorest/codegen/templates/setup.py.jinja2 +2 -3
- package/autorest/jsonrpc/server.py +13 -7
- package/autorest/m2r/__init__.py +18 -6
- package/autorest/m4reformatter/__init__.py +6 -3
- package/autorest/multiapi/__init__.py +57 -31
- package/autorest/multiapi/serializers/__init__.py +26 -24
- package/autorest/multiclient/__init__.py +50 -0
- package/autorest/multiclient/templates/init.py.jinja2 +8 -0
- package/autorest/multiclient/templates/version.py.jinja2 +8 -0
- package/autorest/postprocess/__init__.py +15 -12
- package/autorest/preprocess/__init__.py +47 -8
- package/autorest/preprocess/helpers.py +0 -30
- package/install.py +3 -3
- package/package.json +2 -2
- package/prepare.py +2 -2
- package/requirements.txt +8 -9
- package/run-python3.js +2 -2
- package/setup.py +2 -3
- package/start.py +2 -2
- package/autorest/multiapi/serializers/multiapi_serializer.py +0 -114
|
@@ -11,7 +11,8 @@ 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 .._utils import to_snake_case
|
|
15
|
+
from .. import YamlUpdatePluginAutorest
|
|
15
16
|
|
|
16
17
|
JSON_REGEXP = re.compile(r"^(application|text)/(.+\+)?json$")
|
|
17
18
|
ORIGINAL_ID_TO_UPDATED_TYPE: Dict[int, Dict[str, Any]] = {}
|
|
@@ -431,7 +432,9 @@ def update_client_url(yaml_data: Dict[str, Any]) -> str:
|
|
|
431
432
|
]["uri"]
|
|
432
433
|
|
|
433
434
|
|
|
434
|
-
class M4Reformatter(
|
|
435
|
+
class M4Reformatter(
|
|
436
|
+
YamlUpdatePluginAutorest
|
|
437
|
+
): # pylint: disable=too-many-public-methods
|
|
435
438
|
"""Add Python naming information."""
|
|
436
439
|
|
|
437
440
|
@property
|
|
@@ -1098,7 +1101,7 @@ class M4Reformatter(YamlUpdatePlugin): # pylint: disable=too-many-public-method
|
|
|
1098
1101
|
if yaml_data.get("globalParameters")
|
|
1099
1102
|
else "",
|
|
1100
1103
|
"namespace": self._autorestapi.get_value("namespace")
|
|
1101
|
-
or yaml_data["
|
|
1104
|
+
or to_snake_case(yaml_data["info"]["title"].replace(" ", "")),
|
|
1102
1105
|
}
|
|
1103
1106
|
|
|
1104
1107
|
def update_yaml(self, yaml_data: Dict[str, Any]) -> None:
|
|
@@ -11,53 +11,70 @@ 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
|
-
|
|
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),
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
|
|
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.output_folder,
|
|
45
|
+
user_specified_default_api=self.options.get("default-api"),
|
|
46
|
+
no_async=self.options.get("no-async", False),
|
|
36
47
|
)
|
|
37
|
-
return generator.process()
|
|
38
48
|
|
|
49
|
+
def get_options(self) -> Dict[str, Any]:
|
|
50
|
+
options = {
|
|
51
|
+
"package-name": self._autorestapi.get_value("package-name"),
|
|
52
|
+
"default-api": self._autorestapi.get_value("default-api"),
|
|
53
|
+
"no-async": self._autorestapi.get_value("no-async"),
|
|
54
|
+
}
|
|
55
|
+
return {k: v for k, v in options.items() if v is not None}
|
|
39
56
|
|
|
40
|
-
|
|
57
|
+
|
|
58
|
+
class MultiAPI(ReaderAndWriter): # pylint: disable=abstract-method
|
|
41
59
|
def __init__(
|
|
42
60
|
self,
|
|
43
|
-
|
|
61
|
+
*,
|
|
62
|
+
input_package_name: Optional[str] = None,
|
|
44
63
|
output_folder: str,
|
|
45
|
-
autorestapi: AutorestAPI,
|
|
46
64
|
no_async: Optional[bool] = False,
|
|
47
65
|
user_specified_default_api: Optional[str] = None,
|
|
66
|
+
**kwargs: Any,
|
|
48
67
|
) -> None:
|
|
68
|
+
super().__init__(output_folder=Path(output_folder).resolve(), **kwargs)
|
|
49
69
|
if input_package_name is None:
|
|
50
70
|
raise ValueError(
|
|
51
71
|
"package-name is required, either provide it as args or check your readme configuration"
|
|
52
72
|
)
|
|
53
73
|
self.input_package_name = input_package_name
|
|
54
74
|
_LOGGER.debug("Received package name %s", input_package_name)
|
|
55
|
-
|
|
56
|
-
self.output_folder = Path(output_folder).resolve()
|
|
57
75
|
_LOGGER.debug("Received output-folder %s", output_folder)
|
|
58
76
|
self.output_package_name: str = ""
|
|
59
77
|
self.no_async = no_async
|
|
60
|
-
self._autorestapi = autorestapi
|
|
61
78
|
self.user_specified_default_api = user_specified_default_api
|
|
62
79
|
|
|
63
80
|
@property
|
|
@@ -77,9 +94,7 @@ class MultiAPI:
|
|
|
77
94
|
if self.default_api_version.replace("-", "_") == path_to_version.stem:
|
|
78
95
|
path_to_default_version = path_to_version
|
|
79
96
|
break
|
|
80
|
-
return json.loads(
|
|
81
|
-
self._autorestapi.read_file(path_to_default_version / "_metadata.json")
|
|
82
|
-
)
|
|
97
|
+
return json.loads(self.read_file(path_to_default_version / "_metadata.json"))
|
|
83
98
|
|
|
84
99
|
@property
|
|
85
100
|
def module_name(self) -> str:
|
|
@@ -120,9 +135,7 @@ class MultiAPI:
|
|
|
120
135
|
@property
|
|
121
136
|
def version_path_to_metadata(self) -> Dict[Path, Dict[str, Any]]:
|
|
122
137
|
return {
|
|
123
|
-
version_path: json.loads(
|
|
124
|
-
self._autorestapi.read_file(version_path / "_metadata.json")
|
|
125
|
-
)
|
|
138
|
+
version_path: json.loads(self.read_file(version_path / "_metadata.json"))
|
|
126
139
|
for version_path in self.paths_to_versions
|
|
127
140
|
}
|
|
128
141
|
|
|
@@ -130,9 +143,7 @@ class MultiAPI:
|
|
|
130
143
|
def mod_to_api_version(self) -> Dict[str, str]:
|
|
131
144
|
mod_to_api_version: Dict[str, str] = defaultdict(str)
|
|
132
145
|
for version_path in self.paths_to_versions:
|
|
133
|
-
metadata_json = json.loads(
|
|
134
|
-
self._autorestapi.read_file(version_path / "_metadata.json")
|
|
135
|
-
)
|
|
146
|
+
metadata_json = json.loads(self.read_file(version_path / "_metadata.json"))
|
|
136
147
|
version = metadata_json["chosen_version"]
|
|
137
148
|
total_api_version_list = metadata_json["total_api_version_list"]
|
|
138
149
|
if not version:
|
|
@@ -145,6 +156,10 @@ class MultiAPI:
|
|
|
145
156
|
mod_to_api_version[version_path.name] = version
|
|
146
157
|
return mod_to_api_version
|
|
147
158
|
|
|
159
|
+
@property
|
|
160
|
+
def serializer(self) -> MultiAPISerializer:
|
|
161
|
+
return MultiAPISerializer()
|
|
162
|
+
|
|
148
163
|
def process(self) -> bool:
|
|
149
164
|
_LOGGER.info("Generating multiapi client")
|
|
150
165
|
|
|
@@ -163,8 +178,19 @@ class MultiAPI:
|
|
|
163
178
|
shutil.rmtree(str(self.output_folder / "operations"), ignore_errors=True)
|
|
164
179
|
shutil.rmtree(str(self.output_folder / "models"), ignore_errors=True)
|
|
165
180
|
|
|
166
|
-
multiapi_serializer =
|
|
181
|
+
multiapi_serializer = self.serializer
|
|
167
182
|
multiapi_serializer.serialize(code_model, self.no_async)
|
|
168
183
|
|
|
169
184
|
_LOGGER.info("Done!")
|
|
170
185
|
return True
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
class MultiAPIAutorest(MultiAPI, ReaderAndWriterAutorest):
|
|
189
|
+
def __init__(self, **kwargs: Any) -> None:
|
|
190
|
+
super().__init__(**kwargs)
|
|
191
|
+
|
|
192
|
+
@property
|
|
193
|
+
def serializer(self) -> MultiAPISerializer:
|
|
194
|
+
return MultiAPISerializerAutorest(
|
|
195
|
+
self._autorestapi, output_folder=self.output_folder
|
|
196
|
+
)
|
|
@@ -4,13 +4,14 @@
|
|
|
4
4
|
# license information.
|
|
5
5
|
# --------------------------------------------------------------------------
|
|
6
6
|
from pathlib import Path
|
|
7
|
-
from typing import Any, Optional
|
|
7
|
+
from typing import Any, Optional, Union
|
|
8
8
|
from jinja2 import PackageLoader, Environment
|
|
9
9
|
|
|
10
10
|
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,14 @@ 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__(
|
|
126
|
+
self, autorestapi: AutorestAPI, *, output_folder: Union[str, Path]
|
|
127
|
+
) -> None:
|
|
128
|
+
super().__init__(autorestapi=autorestapi, output_folder=output_folder)
|
|
@@ -0,0 +1,50 @@
|
|
|
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
|
+
import logging
|
|
7
|
+
from typing import Any, Dict
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from jinja2 import Environment, PackageLoader
|
|
10
|
+
from .. import Plugin, PluginAutorest
|
|
11
|
+
|
|
12
|
+
_LOGGER = logging.getLogger(__name__)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class MultiClientPlugin(Plugin): # pylint: disable=abstract-method
|
|
16
|
+
def process(self) -> bool:
|
|
17
|
+
_LOGGER.info("Generating files for multi client")
|
|
18
|
+
|
|
19
|
+
env = Environment(
|
|
20
|
+
loader=PackageLoader("autorest.multiclient", "templates"),
|
|
21
|
+
keep_trailing_newline=True,
|
|
22
|
+
line_statement_prefix="##",
|
|
23
|
+
line_comment_prefix="###",
|
|
24
|
+
trim_blocks=True,
|
|
25
|
+
lstrip_blocks=True,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
# __init__.py
|
|
29
|
+
template = env.get_template("init.py.jinja2")
|
|
30
|
+
self.write_file(Path("__init__.py"), template.render())
|
|
31
|
+
|
|
32
|
+
# _version.py
|
|
33
|
+
template = env.get_template("version.py.jinja2")
|
|
34
|
+
self.write_file(
|
|
35
|
+
Path("_version.py"),
|
|
36
|
+
template.render(
|
|
37
|
+
package_version=self.options.get("package-version") or "1.0.0b1"
|
|
38
|
+
),
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
# py.typed
|
|
42
|
+
self.write_file(Path("py.typed"), "# Marker file for PEP 561.")
|
|
43
|
+
|
|
44
|
+
_LOGGER.info("Generating Done for multi client!")
|
|
45
|
+
return True
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class MultiClientPluginAutorest(MultiClientPlugin, PluginAutorest):
|
|
49
|
+
def get_options(self) -> Dict[str, Any]:
|
|
50
|
+
return {"package-version": self._autorestapi.get_value("package-version")}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# --------------------------------------------------------------------------
|
|
2
|
+
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
3
|
+
# Licensed under the MIT License. See License.txt in the project root for license information.
|
|
4
|
+
# Code generated by Microsoft (R) AutoRest Code Generator.
|
|
5
|
+
# Changes may cause incorrect behavior and will be lost if the code is regenerated.
|
|
6
|
+
# --------------------------------------------------------------------------
|
|
7
|
+
from ._version import VERSION
|
|
8
|
+
__version__ = VERSION
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# coding=utf-8
|
|
2
|
+
# --------------------------------------------------------------------------
|
|
3
|
+
# Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4
|
+
# Licensed under the MIT License. See License.txt in the project root for
|
|
5
|
+
# license information.
|
|
6
|
+
# --------------------------------------------------------------------------
|
|
7
|
+
|
|
8
|
+
VERSION = "{{ package_version }}"
|
|
@@ -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,10 +65,8 @@ 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
|
-
|
|
70
|
-
)
|
|
71
|
-
if not "pkgutil" in file_content:
|
|
68
|
+
file_content = self.read_file(init_file.relative_to(self.output_folder))
|
|
69
|
+
if "pkgutil" not in file_content:
|
|
72
70
|
return dir, namespace
|
|
73
71
|
except StopIteration:
|
|
74
72
|
pass
|
|
@@ -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")}
|
|
@@ -6,10 +6,22 @@
|
|
|
6
6
|
"""The preprocessing autorest plugin.
|
|
7
7
|
"""
|
|
8
8
|
from typing import Callable, Dict, Any, List, Optional
|
|
9
|
-
from
|
|
9
|
+
from .._utils import to_snake_case
|
|
10
|
+
from .helpers import pad_reserved_words, add_redefined_builtin_info
|
|
10
11
|
from .python_mappings import PadType
|
|
11
12
|
|
|
12
|
-
from .. import YamlUpdatePlugin
|
|
13
|
+
from .. import YamlUpdatePlugin, YamlUpdatePluginAutorest
|
|
14
|
+
from .._utils import parse_args
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _remove_paging_maxpagesize(yaml_data: Dict[str, Any]) -> None:
|
|
18
|
+
# we don't expose maxpagesize for version tolerant generation
|
|
19
|
+
# users should be passing this into `by_page`
|
|
20
|
+
yaml_data["parameters"] = [
|
|
21
|
+
p
|
|
22
|
+
for p in yaml_data.get("parameters", [])
|
|
23
|
+
if p["restApiName"].lower() not in ["maxpagesize", "$maxpagesize"]
|
|
24
|
+
]
|
|
13
25
|
|
|
14
26
|
|
|
15
27
|
def update_description(
|
|
@@ -82,9 +94,13 @@ def update_paging_response(yaml_data: Dict[str, Any]) -> None:
|
|
|
82
94
|
)
|
|
83
95
|
|
|
84
96
|
|
|
85
|
-
class PreProcessPlugin(YamlUpdatePlugin):
|
|
97
|
+
class PreProcessPlugin(YamlUpdatePlugin): # pylint: disable=abstract-method
|
|
86
98
|
"""Add Python naming information."""
|
|
87
99
|
|
|
100
|
+
@property
|
|
101
|
+
def version_tolerant(self) -> bool:
|
|
102
|
+
return self.options.get("version-tolerant", True)
|
|
103
|
+
|
|
88
104
|
def get_operation_updater(
|
|
89
105
|
self, yaml_data: Dict[str, Any]
|
|
90
106
|
) -> Callable[[Dict[str, Any]], None]:
|
|
@@ -119,7 +135,7 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
119
135
|
response["discriminator"] = "operation"
|
|
120
136
|
|
|
121
137
|
def _update_lro_operation_helper(self, yaml_data: Dict[str, Any]) -> None:
|
|
122
|
-
azure_arm = self.
|
|
138
|
+
azure_arm = self.options.get("azure-arm", False)
|
|
123
139
|
for response in yaml_data.get("responses", []):
|
|
124
140
|
response["discriminator"] = "lro"
|
|
125
141
|
response["pollerSync"] = (
|
|
@@ -144,13 +160,16 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
144
160
|
def update_lro_paging_operation(self, yaml_data: Dict[str, Any]) -> None:
|
|
145
161
|
self.update_lro_operation(yaml_data)
|
|
146
162
|
self.update_paging_operation(yaml_data)
|
|
163
|
+
yaml_data["discriminator"] = "lropaging"
|
|
147
164
|
for response in yaml_data.get("responses", []):
|
|
148
165
|
response["discriminator"] = "lropaging"
|
|
166
|
+
for overload in yaml_data.get("overloads", []):
|
|
167
|
+
self.update_lro_paging_operation(overload)
|
|
149
168
|
|
|
150
169
|
def update_lro_operation(self, yaml_data: Dict[str, Any]) -> None:
|
|
151
170
|
self.update_operation(yaml_data)
|
|
152
171
|
self._update_lro_operation_helper(yaml_data)
|
|
153
|
-
for overload in yaml_data
|
|
172
|
+
for overload in yaml_data.get("overloads", []):
|
|
154
173
|
self._update_lro_operation_helper(overload)
|
|
155
174
|
|
|
156
175
|
def update_paging_operation(self, yaml_data: Dict[str, Any]) -> None:
|
|
@@ -164,15 +183,18 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
164
183
|
if yaml_data.get("nextOperation")
|
|
165
184
|
else yaml_data["responses"][0]
|
|
166
185
|
)
|
|
167
|
-
|
|
168
|
-
|
|
186
|
+
if self.version_tolerant:
|
|
187
|
+
# if we're in version tolerant, hide the paging model
|
|
169
188
|
returned_response_object["type"]["isPublic"] = False
|
|
189
|
+
_remove_paging_maxpagesize(yaml_data)
|
|
170
190
|
item_type = next(
|
|
171
191
|
p["type"]["elementType"]
|
|
172
192
|
for p in returned_response_object["type"]["properties"]
|
|
173
|
-
if p["restApiName"] == yaml_data
|
|
193
|
+
if p["restApiName"] == (yaml_data.get("itemName") or "value")
|
|
174
194
|
)
|
|
175
195
|
if yaml_data.get("nextOperation"):
|
|
196
|
+
if self.version_tolerant:
|
|
197
|
+
_remove_paging_maxpagesize(yaml_data["nextOperation"])
|
|
176
198
|
yaml_data["nextOperation"]["groupName"] = pad_reserved_words(
|
|
177
199
|
yaml_data["nextOperation"]["groupName"], PadType.OPERATION_GROUP
|
|
178
200
|
)
|
|
@@ -208,3 +230,20 @@ class PreProcessPlugin(YamlUpdatePlugin):
|
|
|
208
230
|
update_client(yaml_data["client"])
|
|
209
231
|
update_types(yaml_data["types"])
|
|
210
232
|
self.update_operation_groups(yaml_data)
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
class PreProcessPluginAutorest(YamlUpdatePluginAutorest, PreProcessPlugin):
|
|
236
|
+
def get_options(self) -> Dict[str, Any]:
|
|
237
|
+
options = {
|
|
238
|
+
"version-tolerant": self._autorestapi.get_boolean_value("version-tolerant"),
|
|
239
|
+
"azure-arm": self._autorestapi.get_boolean_value("azure-arm"),
|
|
240
|
+
}
|
|
241
|
+
return {k: v for k, v in options.items() if v is not None}
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
if __name__ == "__main__":
|
|
245
|
+
# CADL pipeline will call this
|
|
246
|
+
args = parse_args()
|
|
247
|
+
PreProcessPlugin(
|
|
248
|
+
output_folder=args.output_folder, cadl_file=args.cadl_file
|
|
249
|
+
).process()
|
|
@@ -4,39 +4,9 @@
|
|
|
4
4
|
# license information.
|
|
5
5
|
# --------------------------------------------------------------------------
|
|
6
6
|
from typing import Any, Dict
|
|
7
|
-
import re
|
|
8
7
|
from .python_mappings import PadType, RESERVED_WORDS, REDEFINED_BUILTINS
|
|
9
8
|
|
|
10
9
|
|
|
11
|
-
def to_snake_case(name: str) -> str:
|
|
12
|
-
def replace_upper_characters(m) -> str:
|
|
13
|
-
match_str = m.group().lower()
|
|
14
|
-
if m.start() > 0 and name[m.start() - 1] == "_":
|
|
15
|
-
# we are good if a '_' already exists
|
|
16
|
-
return match_str
|
|
17
|
-
# the first letter should not have _
|
|
18
|
-
prefix = "_" if m.start() > 0 else ""
|
|
19
|
-
|
|
20
|
-
# we will add an extra _ if there are multiple upper case chars together
|
|
21
|
-
next_non_upper_case_char_location = m.start() + len(match_str)
|
|
22
|
-
if (
|
|
23
|
-
len(match_str) > 2
|
|
24
|
-
and len(name) - next_non_upper_case_char_location > 1
|
|
25
|
-
and name[next_non_upper_case_char_location].isalpha()
|
|
26
|
-
):
|
|
27
|
-
|
|
28
|
-
return (
|
|
29
|
-
prefix
|
|
30
|
-
+ match_str[: len(match_str) - 1]
|
|
31
|
-
+ "_"
|
|
32
|
-
+ match_str[len(match_str) - 1]
|
|
33
|
-
)
|
|
34
|
-
|
|
35
|
-
return prefix + match_str
|
|
36
|
-
|
|
37
|
-
return re.sub("[A-Z]+", replace_upper_characters, name)
|
|
38
|
-
|
|
39
|
-
|
|
40
10
|
def pad_reserved_words(name: str, pad_type: PadType):
|
|
41
11
|
# we want to pad hidden variables as well
|
|
42
12
|
if not name:
|
package/install.py
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
# license information.
|
|
7
7
|
# --------------------------------------------------------------------------
|
|
8
8
|
import sys
|
|
9
|
-
if not sys.version_info >= (3,
|
|
10
|
-
raise Exception("Autorest for Python extension requires Python 3.
|
|
9
|
+
if not sys.version_info >= (3, 7, 0):
|
|
10
|
+
raise Exception("Autorest for Python extension requires Python 3.7 at least")
|
|
11
11
|
|
|
12
12
|
try:
|
|
13
13
|
import pip
|
|
@@ -20,7 +20,7 @@ except ImportError:
|
|
|
20
20
|
raise Exception("Your Python installation doesn't have venv available")
|
|
21
21
|
|
|
22
22
|
|
|
23
|
-
# Now we have pip and Py >= 3.
|
|
23
|
+
# Now we have pip and Py >= 3.7, go to work
|
|
24
24
|
|
|
25
25
|
import subprocess
|
|
26
26
|
from pathlib import Path
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@autorest/python",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.1.0",
|
|
4
4
|
"description": "The Python extension for generators in AutoRest.",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"prepare": "node run-python3.js prepare.py",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"@autorest/system-requirements": "~1.0.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"@microsoft.azure/autorest.testserver": "^3.3.
|
|
30
|
+
"@microsoft.azure/autorest.testserver": "^3.3.31"
|
|
31
31
|
},
|
|
32
32
|
"files": [
|
|
33
33
|
"autorest/**/*.py",
|
package/prepare.py
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
# license information.
|
|
7
7
|
# --------------------------------------------------------------------------
|
|
8
8
|
import sys
|
|
9
|
-
if not sys.version_info >= (3,
|
|
10
|
-
raise Exception("Autorest for Python extension requires Python 3.
|
|
9
|
+
if not sys.version_info >= (3, 7, 0):
|
|
10
|
+
raise Exception("Autorest for Python extension requires Python 3.7 at least")
|
|
11
11
|
|
|
12
12
|
from pathlib import Path
|
|
13
13
|
import venv
|
package/requirements.txt
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
black==
|
|
2
|
-
click==8.
|
|
3
|
-
docutils==0.18
|
|
4
|
-
Jinja2==3.
|
|
1
|
+
black==22.6.0
|
|
2
|
+
click==8.1.3
|
|
3
|
+
docutils==0.18
|
|
4
|
+
Jinja2==3.1.2
|
|
5
5
|
json-rpc==1.13.0
|
|
6
|
-
|
|
7
|
-
MarkupSafe==2.
|
|
6
|
+
m2r2==0.3.2
|
|
7
|
+
MarkupSafe==2.1.1
|
|
8
8
|
mistune==0.8.4
|
|
9
9
|
mypy-extensions==0.4.3
|
|
10
10
|
pathspec==0.9.0
|
|
11
|
-
platformdirs==2.
|
|
11
|
+
platformdirs==2.5.2
|
|
12
12
|
PyYAML==6.0
|
|
13
|
-
tomli==
|
|
14
|
-
typing-extensions==4.0.1
|
|
13
|
+
tomli==2.0.1
|