@autorest/python 6.14.3 → 6.16.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/autorest/__init__.py +2 -93
- package/autorest/black.py +13 -0
- package/autorest/codegen.py +117 -0
- package/autorest/m2r.py +16 -0
- package/autorest/m4reformatter/__init__.py +1 -1
- package/autorest/multiapi/__init__.py +2 -1
- package/autorest/multiapi/serializers/__init__.py +5 -3
- package/autorest/multiclient/__init__.py +2 -1
- package/autorest/postprocess.py +14 -0
- package/autorest/preprocess.py +20 -0
- package/generator/LICENSE +21 -0
- package/generator/README.md +1 -0
- package/generator/dev_requirements.txt +5 -0
- package/generator/pygen/__init__.py +107 -0
- package/generator/pygen/_version.py +7 -0
- package/{autorest/black/__init__.py → generator/pygen/black.py} +2 -7
- package/{autorest → generator/pygen}/codegen/__init__.py +7 -83
- package/{autorest → generator/pygen}/codegen/models/client.py +2 -1
- package/{autorest → generator/pygen}/codegen/models/combined_type.py +1 -1
- package/{autorest → generator/pygen}/codegen/models/model_type.py +1 -1
- package/{autorest → generator/pygen}/codegen/models/operation.py +2 -0
- package/{autorest → generator/pygen}/codegen/models/operation_group.py +1 -1
- package/{autorest → generator/pygen}/codegen/serializers/__init__.py +16 -30
- package/{autorest → generator/pygen}/codegen/serializers/builder_serializer.py +37 -18
- package/{autorest → generator/pygen}/codegen/serializers/client_serializer.py +1 -1
- package/{autorest → generator/pygen}/codegen/serializers/operations_init_serializer.py +1 -1
- package/{autorest → generator/pygen}/codegen/serializers/parameter_serializer.py +1 -1
- package/{autorest → generator/pygen}/codegen/serializers/sample_serializer.py +2 -2
- package/{autorest → generator/pygen}/codegen/serializers/test_serializer.py +48 -24
- package/{autorest → generator/pygen}/codegen/templates/conftest.py.jinja2 +1 -1
- package/{autorest → generator/pygen}/codegen/templates/request_builder.py.jinja2 +2 -2
- package/generator/pygen/codegen/templates/test.py.jinja2 +50 -0
- package/{autorest/m2r/__init__.py → generator/pygen/m2r.py} +5 -10
- package/{autorest → generator/pygen}/postprocess/__init__.py +1 -6
- package/{autorest → generator/pygen}/preprocess/__init__.py +12 -16
- package/{autorest → generator/pygen}/preprocess/python_mappings.py +6 -4
- package/{autorest/_utils.py → generator/pygen/utils.py} +4 -0
- package/generator/pygen.egg-info/PKG-INFO +25 -0
- package/generator/pygen.egg-info/SOURCES.txt +66 -0
- package/generator/pygen.egg-info/dependency_links.txt +1 -0
- package/generator/pygen.egg-info/requires.txt +4 -0
- package/generator/pygen.egg-info/top_level.txt +1 -0
- package/generator/requirements.txt +12 -0
- package/generator/setup.py +55 -0
- package/package.json +11 -12
- package/requirements.txt +1 -1
- package/scripts/__pycache__/venvtools.cpython-38.pyc +0 -0
- package/scripts/copy-generator.js +19 -0
- package/{install.py → scripts/install.py} +3 -5
- package/{prepare.py → scripts/prepare.py} +7 -4
- package/{start.py → scripts/start.py} +1 -1
- package/{venvtools.py → scripts/venvtools.py} +1 -1
- package/autorest/codegen/templates/test.py.jinja2 +0 -26
- package/run_cadl.py +0 -40
- /package/{autorest → generator/pygen}/codegen/_utils.py +0 -0
- /package/{autorest → generator/pygen}/codegen/models/__init__.py +0 -0
- /package/{autorest → generator/pygen}/codegen/models/base.py +0 -0
- /package/{autorest → generator/pygen}/codegen/models/base_builder.py +0 -0
- /package/{autorest → generator/pygen}/codegen/models/code_model.py +0 -0
- /package/{autorest → generator/pygen}/codegen/models/constant_type.py +0 -0
- /package/{autorest → generator/pygen}/codegen/models/credential_types.py +0 -0
- /package/{autorest → generator/pygen}/codegen/models/dictionary_type.py +0 -0
- /package/{autorest → generator/pygen}/codegen/models/enum_type.py +0 -0
- /package/{autorest → generator/pygen}/codegen/models/imports.py +0 -0
- /package/{autorest → generator/pygen}/codegen/models/list_type.py +0 -0
- /package/{autorest → generator/pygen}/codegen/models/lro_operation.py +0 -0
- /package/{autorest → generator/pygen}/codegen/models/lro_paging_operation.py +0 -0
- /package/{autorest → generator/pygen}/codegen/models/paging_operation.py +0 -0
- /package/{autorest → generator/pygen}/codegen/models/parameter.py +0 -0
- /package/{autorest → generator/pygen}/codegen/models/parameter_list.py +0 -0
- /package/{autorest → generator/pygen}/codegen/models/primitive_types.py +0 -0
- /package/{autorest → generator/pygen}/codegen/models/property.py +0 -0
- /package/{autorest → generator/pygen}/codegen/models/request_builder.py +0 -0
- /package/{autorest → generator/pygen}/codegen/models/request_builder_parameter.py +0 -0
- /package/{autorest → generator/pygen}/codegen/models/response.py +0 -0
- /package/{autorest → generator/pygen}/codegen/models/utils.py +0 -0
- /package/{autorest → generator/pygen}/codegen/serializers/base_serializer.py +0 -0
- /package/{autorest → generator/pygen}/codegen/serializers/enum_serializer.py +0 -0
- /package/{autorest → generator/pygen}/codegen/serializers/general_serializer.py +0 -0
- /package/{autorest → generator/pygen}/codegen/serializers/import_serializer.py +0 -0
- /package/{autorest → generator/pygen}/codegen/serializers/metadata_serializer.py +0 -0
- /package/{autorest → generator/pygen}/codegen/serializers/model_init_serializer.py +0 -0
- /package/{autorest → generator/pygen}/codegen/serializers/model_serializer.py +0 -0
- /package/{autorest → generator/pygen}/codegen/serializers/operation_groups_serializer.py +0 -0
- /package/{autorest → generator/pygen}/codegen/serializers/patch_serializer.py +0 -0
- /package/{autorest → generator/pygen}/codegen/serializers/request_builders_serializer.py +0 -0
- /package/{autorest → generator/pygen}/codegen/serializers/types_serializer.py +0 -0
- /package/{autorest → generator/pygen}/codegen/serializers/utils.py +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/client.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/client_container.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/config.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/config_container.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/enum.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/enum_container.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/init.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/keywords.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/lro_operation.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/lro_paging_operation.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/macros.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/metadata.json.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/model_base.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/model_container.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/model_dpg.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/model_init.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/model_msrest.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/operation.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/operation_group.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/operation_groups_container.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/operation_tools.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/operations_folder_init.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/packaging_templates/CHANGELOG.md.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/packaging_templates/LICENSE.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/packaging_templates/MANIFEST.in.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/packaging_templates/README.md.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/packaging_templates/dev_requirements.txt.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/packaging_templates/setup.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/paging_operation.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/patch.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/pkgutil_init.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/request_builders.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/rest_init.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/sample.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/serialization.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/testpreparer.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/types.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/validation.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/vendor.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/codegen/templates/version.py.jinja2 +0 -0
- /package/{autorest → generator/pygen}/postprocess/get_all.py +0 -0
- /package/{autorest → generator/pygen}/postprocess/venvtools.py +0 -0
- /package/{autorest → generator/pygen}/preprocess/helpers.py +0 -0
- /package/{run-python3.js → scripts/run-python3.js} +0 -0
package/autorest/__init__.py
CHANGED
|
@@ -5,59 +5,18 @@
|
|
|
5
5
|
# --------------------------------------------------------------------------
|
|
6
6
|
import logging
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
import
|
|
9
|
-
from abc import ABC, abstractmethod
|
|
8
|
+
from abc import abstractmethod
|
|
10
9
|
from typing import Any, Dict, Union, List
|
|
11
10
|
|
|
12
11
|
import yaml
|
|
13
12
|
|
|
13
|
+
from pygen import ReaderAndWriter, Plugin, YamlUpdatePlugin
|
|
14
14
|
from .jsonrpc import AutorestAPI
|
|
15
|
-
from ._version import VERSION
|
|
16
15
|
|
|
17
16
|
|
|
18
|
-
__version__ = VERSION
|
|
19
17
|
_LOGGER = logging.getLogger(__name__)
|
|
20
18
|
|
|
21
19
|
|
|
22
|
-
class ReaderAndWriter:
|
|
23
|
-
def __init__(self, *, output_folder: Union[str, Path], **kwargs: Any) -> None:
|
|
24
|
-
self.output_folder = Path(output_folder)
|
|
25
|
-
self._list_file: List[str] = []
|
|
26
|
-
try:
|
|
27
|
-
with open(
|
|
28
|
-
Path(self.output_folder) / Path("..") / Path("python.json"),
|
|
29
|
-
"r",
|
|
30
|
-
encoding="utf-8-sig",
|
|
31
|
-
) as fd:
|
|
32
|
-
python_json = json.load(fd)
|
|
33
|
-
except Exception: # pylint: disable=broad-except
|
|
34
|
-
python_json = {}
|
|
35
|
-
self.options = kwargs
|
|
36
|
-
if python_json:
|
|
37
|
-
_LOGGER.warning("Loading python.json file. This behavior will be depreacted")
|
|
38
|
-
self.options.update(python_json)
|
|
39
|
-
|
|
40
|
-
def read_file(self, path: Union[str, Path]) -> str:
|
|
41
|
-
"""Directly reading from disk"""
|
|
42
|
-
# make path relative to output folder
|
|
43
|
-
try:
|
|
44
|
-
with open(self.output_folder / Path(path), "r", encoding="utf-8-sig") as fd:
|
|
45
|
-
return fd.read()
|
|
46
|
-
except FileNotFoundError:
|
|
47
|
-
return ""
|
|
48
|
-
|
|
49
|
-
def write_file(self, filename: Union[str, Path], file_content: str) -> None:
|
|
50
|
-
"""Directly writing to disk"""
|
|
51
|
-
file_folder = Path(filename).parent
|
|
52
|
-
if not Path.is_dir(self.output_folder / file_folder):
|
|
53
|
-
Path.mkdir(self.output_folder / file_folder, parents=True)
|
|
54
|
-
with open(self.output_folder / Path(filename), "w", encoding="utf-8") as fd:
|
|
55
|
-
fd.write(file_content)
|
|
56
|
-
|
|
57
|
-
def list_file(self) -> List[str]:
|
|
58
|
-
return [str(f) for f in self.output_folder.glob("**/*") if f.is_file()]
|
|
59
|
-
|
|
60
|
-
|
|
61
20
|
class ReaderAndWriterAutorest(ReaderAndWriter):
|
|
62
21
|
def __init__(self, *, output_folder: Union[str, Path], autorestapi: AutorestAPI) -> None:
|
|
63
22
|
super().__init__(output_folder=output_folder)
|
|
@@ -73,23 +32,6 @@ class ReaderAndWriterAutorest(ReaderAndWriter):
|
|
|
73
32
|
return self._autorestapi.list_inputs()
|
|
74
33
|
|
|
75
34
|
|
|
76
|
-
class Plugin(ReaderAndWriter, ABC):
|
|
77
|
-
"""A base class for autorest plugin.
|
|
78
|
-
|
|
79
|
-
:param autorestapi: An autorest API instance
|
|
80
|
-
"""
|
|
81
|
-
|
|
82
|
-
@abstractmethod
|
|
83
|
-
def process(self) -> bool:
|
|
84
|
-
"""The plugin process.
|
|
85
|
-
|
|
86
|
-
:rtype: bool
|
|
87
|
-
:returns: True if everything's ok, False optherwise
|
|
88
|
-
:raises Exception: Could raise any exception, stacktrace will be sent to autorest API
|
|
89
|
-
"""
|
|
90
|
-
raise NotImplementedError()
|
|
91
|
-
|
|
92
|
-
|
|
93
35
|
class PluginAutorest(Plugin, ReaderAndWriterAutorest):
|
|
94
36
|
"""For our Autorest plugins, we want to take autorest api as input as options, then pass it to the Plugin"""
|
|
95
37
|
|
|
@@ -102,39 +44,6 @@ class PluginAutorest(Plugin, ReaderAndWriterAutorest):
|
|
|
102
44
|
"""Get the options bag using the AutorestAPI that we send to the parent plugin"""
|
|
103
45
|
|
|
104
46
|
|
|
105
|
-
class YamlUpdatePlugin(Plugin):
|
|
106
|
-
"""A plugin that update the YAML as input."""
|
|
107
|
-
|
|
108
|
-
def get_yaml(self) -> Dict[str, Any]:
|
|
109
|
-
# cadl file doesn't have to be relative to output folder
|
|
110
|
-
with open(self.options["cadl_file"], "r", encoding="utf-8-sig") as fd:
|
|
111
|
-
return yaml.safe_load(fd.read())
|
|
112
|
-
|
|
113
|
-
def write_yaml(self, yaml_string: str) -> None:
|
|
114
|
-
with open(self.options["cadl_file"], "w", encoding="utf-8-sig") as fd:
|
|
115
|
-
fd.write(yaml_string)
|
|
116
|
-
|
|
117
|
-
def process(self) -> bool:
|
|
118
|
-
# List the input file, should be only one
|
|
119
|
-
yaml_data = self.get_yaml()
|
|
120
|
-
|
|
121
|
-
self.update_yaml(yaml_data)
|
|
122
|
-
|
|
123
|
-
yaml_string = yaml.safe_dump(yaml_data)
|
|
124
|
-
|
|
125
|
-
self.write_yaml(yaml_string)
|
|
126
|
-
return True
|
|
127
|
-
|
|
128
|
-
@abstractmethod
|
|
129
|
-
def update_yaml(self, yaml_data: Dict[str, Any]) -> None:
|
|
130
|
-
"""The code-model-v4-no-tags yaml model tree.
|
|
131
|
-
|
|
132
|
-
:rtype: updated yaml
|
|
133
|
-
:raises Exception: Could raise any exception, stacktrace will be sent to autorest API
|
|
134
|
-
"""
|
|
135
|
-
raise NotImplementedError()
|
|
136
|
-
|
|
137
|
-
|
|
138
47
|
class YamlUpdatePluginAutorest(YamlUpdatePlugin, PluginAutorest): # pylint: disable=abstract-method
|
|
139
48
|
def get_yaml(self) -> Dict[str, Any]:
|
|
140
49
|
return yaml.safe_load(self.read_file("code-model-v4-no-tags.yaml"))
|
|
@@ -0,0 +1,13 @@
|
|
|
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 Dict, Any
|
|
7
|
+
from pygen.black import BlackScriptPlugin
|
|
8
|
+
from . import PluginAutorest
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class BlackScriptPluginAutorest(BlackScriptPlugin, PluginAutorest):
|
|
12
|
+
def get_options(self) -> Dict[str, Any]:
|
|
13
|
+
return {"output_folder": self._autorestapi.get_value("outputFolderUri")}
|
|
@@ -0,0 +1,117 @@
|
|
|
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 Dict, Any, Union
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
import yaml
|
|
10
|
+
|
|
11
|
+
from pygen.codegen import CodeGenerator
|
|
12
|
+
from pygen.codegen.models import CodeModel
|
|
13
|
+
from pygen.codegen.serializers import JinjaSerializer
|
|
14
|
+
|
|
15
|
+
from . import ReaderAndWriterAutorest
|
|
16
|
+
from .jsonrpc import AutorestAPI
|
|
17
|
+
from . import PluginAutorest
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
_LOGGER = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class JinjaSerializerAutorest(JinjaSerializer, ReaderAndWriterAutorest):
|
|
24
|
+
def __init__(
|
|
25
|
+
self,
|
|
26
|
+
autorestapi: AutorestAPI,
|
|
27
|
+
code_model: CodeModel,
|
|
28
|
+
*,
|
|
29
|
+
output_folder: Union[str, Path],
|
|
30
|
+
**kwargs: Any,
|
|
31
|
+
) -> None:
|
|
32
|
+
super().__init__( # type: ignore
|
|
33
|
+
autorestapi=autorestapi,
|
|
34
|
+
code_model=code_model,
|
|
35
|
+
output_folder=output_folder,
|
|
36
|
+
**kwargs,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
class CodeGeneratorAutorest(CodeGenerator, PluginAutorest):
|
|
41
|
+
def get_options(self) -> Dict[str, Any]:
|
|
42
|
+
if self._autorestapi.get_boolean_value("python3-only") is False:
|
|
43
|
+
_LOGGER.warning("You have passed in --python3-only=False. We have force overriden this to True.")
|
|
44
|
+
if self._autorestapi.get_boolean_value("add-python3-operation-files"):
|
|
45
|
+
_LOGGER.warning(
|
|
46
|
+
"You have passed in --add-python3-operation-files. "
|
|
47
|
+
"This flag no longer has an effect bc all SDKs are now Python3 only."
|
|
48
|
+
)
|
|
49
|
+
if self._autorestapi.get_boolean_value("reformat-next-link"):
|
|
50
|
+
_LOGGER.warning(
|
|
51
|
+
"You have passed in --reformat-next-link. We have force overriden "
|
|
52
|
+
"this to False because we no longer reformat initial query parameters into next "
|
|
53
|
+
"calls unless explicitly defined in the service definition."
|
|
54
|
+
)
|
|
55
|
+
options = {
|
|
56
|
+
"azure-arm": self._autorestapi.get_boolean_value("azure-arm"),
|
|
57
|
+
"header-text": self._autorestapi.get_value("header-text"),
|
|
58
|
+
"low-level-client": self._autorestapi.get_boolean_value("low-level-client", False),
|
|
59
|
+
"version-tolerant": self._autorestapi.get_boolean_value("version-tolerant", True),
|
|
60
|
+
"show-operations": self._autorestapi.get_boolean_value("show-operations"),
|
|
61
|
+
"python3-only": self._autorestapi.get_boolean_value("python3-only"),
|
|
62
|
+
"head-as-boolean": self._autorestapi.get_boolean_value("head-as-boolean", False),
|
|
63
|
+
"keep-version-file": self._autorestapi.get_boolean_value("keep-version-file"),
|
|
64
|
+
"no-async": self._autorestapi.get_boolean_value("no-async"),
|
|
65
|
+
"no-namespace-folders": self._autorestapi.get_boolean_value("no-namespace-folders"),
|
|
66
|
+
"basic-setup-py": self._autorestapi.get_boolean_value("basic-setup-py"),
|
|
67
|
+
"package-name": self._autorestapi.get_value("package-name"),
|
|
68
|
+
"package-version": self._autorestapi.get_value("package-version"),
|
|
69
|
+
"client-side-validation": self._autorestapi.get_boolean_value("client-side-validation"),
|
|
70
|
+
"tracing": self._autorestapi.get_boolean_value("trace"),
|
|
71
|
+
"multiapi": self._autorestapi.get_boolean_value("multiapi", False),
|
|
72
|
+
"polymorphic-examples": self._autorestapi.get_value("polymorphic-examples"),
|
|
73
|
+
"models-mode": self._autorestapi.get_value("models-mode"),
|
|
74
|
+
"builders-visibility": self._autorestapi.get_value("builders-visibility"),
|
|
75
|
+
"show-send-request": self._autorestapi.get_boolean_value("show-send-request"),
|
|
76
|
+
"only-path-and-body-params-positional": self._autorestapi.get_boolean_value(
|
|
77
|
+
"only-path-and-body-params-positional"
|
|
78
|
+
),
|
|
79
|
+
"combine-operation-files": self._autorestapi.get_boolean_value("combine-operation-files"),
|
|
80
|
+
"package-mode": self._autorestapi.get_value("package-mode"),
|
|
81
|
+
"package-pprint-name": self._autorestapi.get_value("package-pprint-name"),
|
|
82
|
+
"packaging-files-config": self._autorestapi.get_value("package-configuration"),
|
|
83
|
+
"default-optional-constants-to-none": self._autorestapi.get_boolean_value(
|
|
84
|
+
"default-optional-constants-to-none"
|
|
85
|
+
),
|
|
86
|
+
"generate-sample": self._autorestapi.get_boolean_value("generate-sample"),
|
|
87
|
+
"generate-test": self._autorestapi.get_boolean_value("generate-test"),
|
|
88
|
+
"default-api-version": self._autorestapi.get_value("default-api-version"),
|
|
89
|
+
}
|
|
90
|
+
return {k: v for k, v in options.items() if v is not None}
|
|
91
|
+
|
|
92
|
+
def get_yaml(self) -> Dict[str, Any]:
|
|
93
|
+
inputs = self._autorestapi.list_inputs()
|
|
94
|
+
_LOGGER.debug("Possible Inputs: %s", inputs)
|
|
95
|
+
if "code-model-v4-no-tags.yaml" not in inputs:
|
|
96
|
+
raise ValueError("code-model-v4-no-tags.yaml must be a possible input")
|
|
97
|
+
|
|
98
|
+
if self._autorestapi.get_value("input-yaml"):
|
|
99
|
+
input_yaml = self._autorestapi.get_value("input-yaml")
|
|
100
|
+
file_content = self._autorestapi.read_file(input_yaml)
|
|
101
|
+
else:
|
|
102
|
+
inputs = self._autorestapi.list_inputs()
|
|
103
|
+
_LOGGER.debug("Possible Inputs: %s", inputs)
|
|
104
|
+
if "code-model-v4-no-tags.yaml" not in inputs:
|
|
105
|
+
raise ValueError("code-model-v4-no-tags.yaml must be a possible input")
|
|
106
|
+
|
|
107
|
+
file_content = self._autorestapi.read_file("code-model-v4-no-tags.yaml")
|
|
108
|
+
|
|
109
|
+
# Parse the received YAML
|
|
110
|
+
return yaml.safe_load(file_content)
|
|
111
|
+
|
|
112
|
+
def get_serializer(self, code_model: CodeModel):
|
|
113
|
+
return JinjaSerializerAutorest(
|
|
114
|
+
self._autorestapi,
|
|
115
|
+
code_model,
|
|
116
|
+
output_folder=self.output_folder,
|
|
117
|
+
)
|
package/autorest/m2r.py
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
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
|
+
"""An autorest MD to RST plugin.
|
|
7
|
+
"""
|
|
8
|
+
from typing import Any, Dict
|
|
9
|
+
|
|
10
|
+
from pygen.m2r import M2R
|
|
11
|
+
from . import YamlUpdatePluginAutorest
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class M2RAutorest(YamlUpdatePluginAutorest, M2R):
|
|
15
|
+
def get_options(self) -> Dict[str, Any]:
|
|
16
|
+
return {}
|
|
@@ -10,12 +10,13 @@ import json
|
|
|
10
10
|
from collections import defaultdict
|
|
11
11
|
from pathlib import Path
|
|
12
12
|
from typing import Dict, List, Optional, cast, Any
|
|
13
|
+
from pygen import Plugin, ReaderAndWriter
|
|
13
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
18
|
|
|
18
|
-
from .. import
|
|
19
|
+
from .. import PluginAutorest, ReaderAndWriterAutorest
|
|
19
20
|
|
|
20
21
|
_LOGGER = logging.getLogger(__name__)
|
|
21
22
|
|
|
@@ -6,13 +6,15 @@
|
|
|
6
6
|
from pathlib import Path
|
|
7
7
|
from typing import Any, Optional, Union, List
|
|
8
8
|
from jinja2 import PackageLoader, Environment
|
|
9
|
+
from pygen import ReaderAndWriter
|
|
10
|
+
from pygen.utils import build_policies
|
|
9
11
|
|
|
10
12
|
from .import_serializer import FileImportSerializer
|
|
11
13
|
|
|
12
14
|
from ...jsonrpc import AutorestAPI
|
|
13
15
|
from ..models import CodeModel, GlobalParameter
|
|
14
|
-
from ... import
|
|
15
|
-
|
|
16
|
+
from ... import ReaderAndWriterAutorest
|
|
17
|
+
|
|
16
18
|
|
|
17
19
|
__all__ = [
|
|
18
20
|
"MultiAPISerializer",
|
|
@@ -123,7 +125,7 @@ class MultiAPISerializer(ReaderAndWriter): # pylint: disable=abstract-method
|
|
|
123
125
|
|
|
124
126
|
if not code_model.client.client_side_validation:
|
|
125
127
|
codegen_env = Environment(
|
|
126
|
-
loader=PackageLoader("
|
|
128
|
+
loader=PackageLoader("pygen.codegen", "templates"),
|
|
127
129
|
keep_trailing_newline=True,
|
|
128
130
|
line_statement_prefix="##",
|
|
129
131
|
line_comment_prefix="###",
|
|
@@ -7,7 +7,8 @@ import logging
|
|
|
7
7
|
from typing import Any, Dict
|
|
8
8
|
from pathlib import Path
|
|
9
9
|
from jinja2 import Environment, PackageLoader
|
|
10
|
-
from
|
|
10
|
+
from pygen import Plugin
|
|
11
|
+
from .. import PluginAutorest
|
|
11
12
|
|
|
12
13
|
_LOGGER = logging.getLogger(__name__)
|
|
13
14
|
|
|
@@ -0,0 +1,14 @@
|
|
|
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 Any, Dict
|
|
7
|
+
|
|
8
|
+
from pygen.postprocess import PostProcessPlugin
|
|
9
|
+
from . import PluginAutorest
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class PostProcessPluginAutorest(PostProcessPlugin, PluginAutorest):
|
|
13
|
+
def get_options(self) -> Dict[str, Any]:
|
|
14
|
+
return {"outputFolderUri": self._autorestapi.get_value("outputFolderUri")}
|
|
@@ -0,0 +1,20 @@
|
|
|
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
|
+
"""The preprocessing autorest plugin.
|
|
7
|
+
"""
|
|
8
|
+
from typing import Dict, Any
|
|
9
|
+
from pygen.preprocess import PreProcessPlugin
|
|
10
|
+
from . import YamlUpdatePluginAutorest
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class PreProcessPluginAutorest(YamlUpdatePluginAutorest, PreProcessPlugin):
|
|
14
|
+
def get_options(self) -> Dict[str, Any]:
|
|
15
|
+
options = {
|
|
16
|
+
"version-tolerant": self._autorestapi.get_boolean_value("version-tolerant"),
|
|
17
|
+
"azure-arm": self._autorestapi.get_boolean_value("azure-arm"),
|
|
18
|
+
"models-mode": self._autorestapi.get_value("models-mode"),
|
|
19
|
+
}
|
|
20
|
+
return {k: v for k, v in options.items() if v is not None}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Microsoft Corporation. All rights reserved.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
# Core Library for Python Generation
|
|
@@ -0,0 +1,107 @@
|
|
|
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 pathlib import Path
|
|
8
|
+
import json
|
|
9
|
+
from abc import ABC, abstractmethod
|
|
10
|
+
from typing import Any, Dict, Union, List
|
|
11
|
+
|
|
12
|
+
import yaml
|
|
13
|
+
|
|
14
|
+
from ._version import VERSION
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
__version__ = VERSION
|
|
18
|
+
_LOGGER = logging.getLogger(__name__)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class ReaderAndWriter:
|
|
22
|
+
def __init__(self, *, output_folder: Union[str, Path], **kwargs: Any) -> None:
|
|
23
|
+
self.output_folder = Path(output_folder)
|
|
24
|
+
self._list_file: List[str] = []
|
|
25
|
+
try:
|
|
26
|
+
with open(
|
|
27
|
+
Path(self.output_folder) / Path("..") / Path("python.json"),
|
|
28
|
+
"r",
|
|
29
|
+
encoding="utf-8-sig",
|
|
30
|
+
) as fd:
|
|
31
|
+
python_json = json.load(fd)
|
|
32
|
+
except Exception: # pylint: disable=broad-except
|
|
33
|
+
python_json = {}
|
|
34
|
+
self.options = kwargs
|
|
35
|
+
if python_json:
|
|
36
|
+
_LOGGER.warning("Loading python.json file. This behavior will be depreacted")
|
|
37
|
+
self.options.update(python_json)
|
|
38
|
+
|
|
39
|
+
def read_file(self, path: Union[str, Path]) -> str:
|
|
40
|
+
"""Directly reading from disk"""
|
|
41
|
+
# make path relative to output folder
|
|
42
|
+
try:
|
|
43
|
+
with open(self.output_folder / Path(path), "r", encoding="utf-8-sig") as fd:
|
|
44
|
+
return fd.read()
|
|
45
|
+
except FileNotFoundError:
|
|
46
|
+
return ""
|
|
47
|
+
|
|
48
|
+
def write_file(self, filename: Union[str, Path], file_content: str) -> None:
|
|
49
|
+
"""Directly writing to disk"""
|
|
50
|
+
file_folder = Path(filename).parent
|
|
51
|
+
if not Path.is_dir(self.output_folder / file_folder):
|
|
52
|
+
Path.mkdir(self.output_folder / file_folder, parents=True)
|
|
53
|
+
with open(self.output_folder / Path(filename), "w", encoding="utf-8") as fd:
|
|
54
|
+
fd.write(file_content)
|
|
55
|
+
|
|
56
|
+
def list_file(self) -> List[str]:
|
|
57
|
+
return [str(f) for f in self.output_folder.glob("**/*") if f.is_file()]
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
class Plugin(ReaderAndWriter, ABC):
|
|
61
|
+
"""A base class for autorest plugin.
|
|
62
|
+
|
|
63
|
+
:param autorestapi: An autorest API instance
|
|
64
|
+
"""
|
|
65
|
+
|
|
66
|
+
@abstractmethod
|
|
67
|
+
def process(self) -> bool:
|
|
68
|
+
"""The plugin process.
|
|
69
|
+
|
|
70
|
+
:rtype: bool
|
|
71
|
+
:returns: True if everything's ok, False optherwise
|
|
72
|
+
:raises Exception: Could raise any exception, stacktrace will be sent to autorest API
|
|
73
|
+
"""
|
|
74
|
+
raise NotImplementedError()
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class YamlUpdatePlugin(Plugin):
|
|
78
|
+
"""A plugin that update the YAML as input."""
|
|
79
|
+
|
|
80
|
+
def get_yaml(self) -> Dict[str, Any]:
|
|
81
|
+
# cadl file doesn't have to be relative to output folder
|
|
82
|
+
with open(self.options["cadl_file"], "r", encoding="utf-8-sig") as fd:
|
|
83
|
+
return yaml.safe_load(fd.read())
|
|
84
|
+
|
|
85
|
+
def write_yaml(self, yaml_string: str) -> None:
|
|
86
|
+
with open(self.options["cadl_file"], "w", encoding="utf-8-sig") as fd:
|
|
87
|
+
fd.write(yaml_string)
|
|
88
|
+
|
|
89
|
+
def process(self) -> bool:
|
|
90
|
+
# List the input file, should be only one
|
|
91
|
+
yaml_data = self.get_yaml()
|
|
92
|
+
|
|
93
|
+
self.update_yaml(yaml_data)
|
|
94
|
+
|
|
95
|
+
yaml_string = yaml.safe_dump(yaml_data)
|
|
96
|
+
|
|
97
|
+
self.write_yaml(yaml_string)
|
|
98
|
+
return True
|
|
99
|
+
|
|
100
|
+
@abstractmethod
|
|
101
|
+
def update_yaml(self, yaml_data: Dict[str, Any]) -> None:
|
|
102
|
+
"""The code-model-v4-no-tags yaml model tree.
|
|
103
|
+
|
|
104
|
+
:rtype: updated yaml
|
|
105
|
+
:raises Exception: Could raise any exception, stacktrace will be sent to autorest API
|
|
106
|
+
"""
|
|
107
|
+
raise NotImplementedError()
|
|
@@ -0,0 +1,7 @@
|
|
|
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
|
+
|
|
7
|
+
VERSION = "0.1.0"
|
|
@@ -10,8 +10,8 @@ from typing import Any, Dict
|
|
|
10
10
|
import black
|
|
11
11
|
from black.report import NothingChanged
|
|
12
12
|
|
|
13
|
-
from
|
|
14
|
-
from
|
|
13
|
+
from . import Plugin
|
|
14
|
+
from .utils import parse_args
|
|
15
15
|
|
|
16
16
|
_LOGGER = logging.getLogger("blib2to3")
|
|
17
17
|
|
|
@@ -65,11 +65,6 @@ class BlackScriptPlugin(Plugin): # pylint: disable=abstract-method
|
|
|
65
65
|
self.write_file(file, file_content)
|
|
66
66
|
|
|
67
67
|
|
|
68
|
-
class BlackScriptPluginAutorest(BlackScriptPlugin, PluginAutorest):
|
|
69
|
-
def get_options(self) -> Dict[str, Any]:
|
|
70
|
-
return {"output_folder": self._autorestapi.get_value("outputFolderUri")}
|
|
71
|
-
|
|
72
|
-
|
|
73
68
|
if __name__ == "__main__":
|
|
74
69
|
# CADL pipeline will call this
|
|
75
70
|
args, unknown_args = parse_args(need_cadl_file=False)
|
|
@@ -9,10 +9,10 @@ from pathlib import Path
|
|
|
9
9
|
import yaml
|
|
10
10
|
|
|
11
11
|
|
|
12
|
-
from .. import Plugin
|
|
13
|
-
from ..
|
|
12
|
+
from .. import Plugin
|
|
13
|
+
from ..utils import parse_args
|
|
14
14
|
from .models.code_model import CodeModel
|
|
15
|
-
from .serializers import JinjaSerializer
|
|
15
|
+
from .serializers import JinjaSerializer
|
|
16
16
|
from ._utils import DEFAULT_HEADER_TEXT, VALID_PACKAGE_MODE, TYPESPEC_PACKAGE_MODE
|
|
17
17
|
|
|
18
18
|
|
|
@@ -164,6 +164,10 @@ class OptionsRetriever:
|
|
|
164
164
|
except AttributeError:
|
|
165
165
|
return packaging_files_config
|
|
166
166
|
|
|
167
|
+
@property
|
|
168
|
+
def package_version(self) -> Optional[str]:
|
|
169
|
+
return str(self.options.get("package-version", ""))
|
|
170
|
+
|
|
167
171
|
|
|
168
172
|
class CodeGenerator(Plugin):
|
|
169
173
|
def __init__(self, *args, **kwargs: Any) -> None:
|
|
@@ -324,86 +328,6 @@ class CodeGenerator(Plugin):
|
|
|
324
328
|
return True
|
|
325
329
|
|
|
326
330
|
|
|
327
|
-
class CodeGeneratorAutorest(CodeGenerator, PluginAutorest):
|
|
328
|
-
def get_options(self) -> Dict[str, Any]:
|
|
329
|
-
if self._autorestapi.get_boolean_value("python3-only") is False:
|
|
330
|
-
_LOGGER.warning("You have passed in --python3-only=False. We have force overriden this to True.")
|
|
331
|
-
if self._autorestapi.get_boolean_value("add-python3-operation-files"):
|
|
332
|
-
_LOGGER.warning(
|
|
333
|
-
"You have passed in --add-python3-operation-files. "
|
|
334
|
-
"This flag no longer has an effect bc all SDKs are now Python3 only."
|
|
335
|
-
)
|
|
336
|
-
if self._autorestapi.get_boolean_value("reformat-next-link"):
|
|
337
|
-
_LOGGER.warning(
|
|
338
|
-
"You have passed in --reformat-next-link. We have force overriden "
|
|
339
|
-
"this to False because we no longer reformat initial query parameters into next "
|
|
340
|
-
"calls unless explicitly defined in the service definition."
|
|
341
|
-
)
|
|
342
|
-
options = {
|
|
343
|
-
"azure-arm": self._autorestapi.get_boolean_value("azure-arm"),
|
|
344
|
-
"header-text": self._autorestapi.get_value("header-text"),
|
|
345
|
-
"low-level-client": self._autorestapi.get_boolean_value("low-level-client", False),
|
|
346
|
-
"version-tolerant": self._autorestapi.get_boolean_value("version-tolerant", True),
|
|
347
|
-
"show-operations": self._autorestapi.get_boolean_value("show-operations"),
|
|
348
|
-
"python3-only": self._autorestapi.get_boolean_value("python3-only"),
|
|
349
|
-
"head-as-boolean": self._autorestapi.get_boolean_value("head-as-boolean", False),
|
|
350
|
-
"keep-version-file": self._autorestapi.get_boolean_value("keep-version-file"),
|
|
351
|
-
"no-async": self._autorestapi.get_boolean_value("no-async"),
|
|
352
|
-
"no-namespace-folders": self._autorestapi.get_boolean_value("no-namespace-folders"),
|
|
353
|
-
"basic-setup-py": self._autorestapi.get_boolean_value("basic-setup-py"),
|
|
354
|
-
"package-name": self._autorestapi.get_value("package-name"),
|
|
355
|
-
"package-version": self._autorestapi.get_value("package-version"),
|
|
356
|
-
"client-side-validation": self._autorestapi.get_boolean_value("client-side-validation"),
|
|
357
|
-
"tracing": self._autorestapi.get_boolean_value("trace"),
|
|
358
|
-
"multiapi": self._autorestapi.get_boolean_value("multiapi", False),
|
|
359
|
-
"polymorphic-examples": self._autorestapi.get_value("polymorphic-examples"),
|
|
360
|
-
"models-mode": self._autorestapi.get_value("models-mode"),
|
|
361
|
-
"builders-visibility": self._autorestapi.get_value("builders-visibility"),
|
|
362
|
-
"show-send-request": self._autorestapi.get_boolean_value("show-send-request"),
|
|
363
|
-
"only-path-and-body-params-positional": self._autorestapi.get_boolean_value(
|
|
364
|
-
"only-path-and-body-params-positional"
|
|
365
|
-
),
|
|
366
|
-
"combine-operation-files": self._autorestapi.get_boolean_value("combine-operation-files"),
|
|
367
|
-
"package-mode": self._autorestapi.get_value("package-mode"),
|
|
368
|
-
"package-pprint-name": self._autorestapi.get_value("package-pprint-name"),
|
|
369
|
-
"packaging-files-config": self._autorestapi.get_value("package-configuration"),
|
|
370
|
-
"default-optional-constants-to-none": self._autorestapi.get_boolean_value(
|
|
371
|
-
"default-optional-constants-to-none"
|
|
372
|
-
),
|
|
373
|
-
"generate-sample": self._autorestapi.get_boolean_value("generate-sample"),
|
|
374
|
-
"generate-test": self._autorestapi.get_boolean_value("generate-test"),
|
|
375
|
-
"default-api-version": self._autorestapi.get_value("default-api-version"),
|
|
376
|
-
}
|
|
377
|
-
return {k: v for k, v in options.items() if v is not None}
|
|
378
|
-
|
|
379
|
-
def get_yaml(self) -> Dict[str, Any]:
|
|
380
|
-
inputs = self._autorestapi.list_inputs()
|
|
381
|
-
_LOGGER.debug("Possible Inputs: %s", inputs)
|
|
382
|
-
if "code-model-v4-no-tags.yaml" not in inputs:
|
|
383
|
-
raise ValueError("code-model-v4-no-tags.yaml must be a possible input")
|
|
384
|
-
|
|
385
|
-
if self._autorestapi.get_value("input-yaml"):
|
|
386
|
-
input_yaml = self._autorestapi.get_value("input-yaml")
|
|
387
|
-
file_content = self._autorestapi.read_file(input_yaml)
|
|
388
|
-
else:
|
|
389
|
-
inputs = self._autorestapi.list_inputs()
|
|
390
|
-
_LOGGER.debug("Possible Inputs: %s", inputs)
|
|
391
|
-
if "code-model-v4-no-tags.yaml" not in inputs:
|
|
392
|
-
raise ValueError("code-model-v4-no-tags.yaml must be a possible input")
|
|
393
|
-
|
|
394
|
-
file_content = self._autorestapi.read_file("code-model-v4-no-tags.yaml")
|
|
395
|
-
|
|
396
|
-
# Parse the received YAML
|
|
397
|
-
return yaml.safe_load(file_content)
|
|
398
|
-
|
|
399
|
-
def get_serializer(self, code_model: CodeModel):
|
|
400
|
-
return JinjaSerializerAutorest(
|
|
401
|
-
self._autorestapi,
|
|
402
|
-
code_model,
|
|
403
|
-
output_folder=self.output_folder,
|
|
404
|
-
)
|
|
405
|
-
|
|
406
|
-
|
|
407
331
|
if __name__ == "__main__":
|
|
408
332
|
# CADL pipeline will call this
|
|
409
333
|
parsed_args, unknown_args = parse_args()
|