@autorest/python 6.0.0 → 6.1.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.
Files changed (34) hide show
  1. package/ChangeLog.md +56 -0
  2. package/README.md +21 -2
  3. package/autorest/__init__.py +80 -14
  4. package/autorest/_utils.py +56 -0
  5. package/autorest/black/__init__.py +27 -14
  6. package/autorest/codegen/__init__.py +131 -90
  7. package/autorest/codegen/_utils.py +14 -0
  8. package/autorest/codegen/models/__init__.py +10 -1
  9. package/autorest/codegen/models/model_type.py +12 -1
  10. package/autorest/codegen/serializers/__init__.py +58 -58
  11. package/autorest/codegen/serializers/builder_serializer.py +1 -3
  12. package/autorest/codegen/serializers/client_serializer.py +6 -0
  13. package/autorest/codegen/templates/README.md.jinja2 +3 -3
  14. package/autorest/codegen/templates/setup.py.jinja2 +1 -2
  15. package/autorest/jsonrpc/server.py +13 -7
  16. package/autorest/m2r/__init__.py +18 -6
  17. package/autorest/m4reformatter/__init__.py +6 -3
  18. package/autorest/multiapi/__init__.py +57 -31
  19. package/autorest/multiapi/serializers/__init__.py +26 -24
  20. package/autorest/multiclient/__init__.py +50 -0
  21. package/autorest/multiclient/templates/init.py.jinja2 +8 -0
  22. package/autorest/multiclient/templates/version.py.jinja2 +8 -0
  23. package/autorest/postprocess/__init__.py +15 -12
  24. package/autorest/preprocess/__init__.py +24 -5
  25. package/autorest/preprocess/helpers.py +0 -30
  26. package/install.py +3 -3
  27. package/package.json +3 -2
  28. package/prepare.py +2 -2
  29. package/requirements.txt +8 -9
  30. package/run-python3.js +2 -2
  31. package/run_cadl.py +26 -0
  32. package/setup.py +2 -3
  33. package/start.py +2 -2
  34. package/autorest/multiapi/serializers/multiapi_serializer.py +0 -114
package/ChangeLog.md CHANGED
@@ -1,5 +1,61 @@
1
1
  # Release History
2
2
 
3
+ ### 2022-07-20 - 6.1.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
+ **Other Changes**
15
+
16
+ - Get skeleton for cadl generation released #1358
17
+
18
+ ### 2022-07-20 - 6.1.0
19
+
20
+ | Library | Min Version |
21
+ | ----------------------------------------------------------------------- | ----------- |
22
+ | `@autorest/core` | `3.8.1` |
23
+ | `@autorest/modelerfour` | `4.23.5` |
24
+ | `azure-core` dep of generated code | `1.24.0` |
25
+ | `isodate` dep of generated code | `0.6.1` |
26
+ | `msrest` dep of generated code (If generating legacy code) | `0.7.1` |
27
+ | `azure-mgmt-core` dep of generated code (If generating mgmt plane code) | `1.3.0` |
28
+
29
+ **New Features**
30
+
31
+ - Add new plugin `MultiClient` and new flag `--multiclientscript` to handle package structure of multi client #1328
32
+
33
+ **Bug Fixes**
34
+
35
+ - Fallback unrecognized type as string to avoid a fatal error. #1341
36
+ - Fix regression in default namespace for SDKs generated without `--namespace` flag #1354
37
+
38
+ **Other Changes**
39
+
40
+ - Generated code no longer supports Python 3.6 #1353
41
+ - Order json input and response template entries by whether they are required or not #1335
42
+ - Reduce extreme amount of `black` logs when running in `--debug` mode to just log errors
43
+
44
+ ### 2022-06-29 - 6.0.1
45
+
46
+ | Library | Min Version |
47
+ | ----------------------------------------------------------------------- | ----------- |
48
+ | `@autorest/core` | `3.8.1` |
49
+ | `@autorest/modelerfour` | `4.23.5` |
50
+ | `azure-core` dep of generated code | `1.24.0` |
51
+ | `isodate` dep of generated code | `0.6.1` |
52
+ | `msrest` dep of generated code (If generating legacy code) | `0.7.1` |
53
+ | `azure-mgmt-core` dep of generated code (If generating mgmt plane code) | `1.3.0` |
54
+
55
+ **Bug Fixes**
56
+
57
+ - Ignore linting error for clients with no credentials #1333
58
+
3
59
  ### 2022-06-24 - 6.0.0
4
60
 
5
61
  | Library | Min Version |
package/README.md CHANGED
@@ -23,7 +23,7 @@ contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additio
23
23
 
24
24
  #### Python code gen
25
25
 
26
- ```yaml !$(multiapiscript)
26
+ ```yaml !$(multiapiscript) && !$(multiclientscript)
27
27
  # default values for version tolerant and black
28
28
  black: true
29
29
  ```
@@ -43,7 +43,7 @@ modelerfour:
43
43
  allow-no-input: true
44
44
  ```
45
45
 
46
- ```yaml !$(multiapiscript)
46
+ ```yaml !$(multiapiscript) && !$(multiclientscript)
47
47
  pass-thru:
48
48
  - model-deduplicator
49
49
  - subset-reducer
@@ -161,6 +161,25 @@ scope-postprocess/emitter:
161
161
  output-artifact: python-files
162
162
  ```
163
163
 
164
+ # Multi Client pipeline
165
+
166
+ ```yaml $(multiclientscript)
167
+ pipeline:
168
+ python/multiclientscript:
169
+ scope: multiclientscript
170
+ output-artifact: python-files
171
+
172
+ python/multiclientscript/emitter:
173
+ input: multiclientscript
174
+ scope: scope-multiclientscript/emitter
175
+
176
+ scope-multiclientscript/emitter:
177
+ input-artifact: python-files
178
+ output-uri-expr: $key
179
+
180
+ output-artifact: python-files
181
+ ```
182
+
164
183
  # Help
165
184
 
166
185
  ```yaml
@@ -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,15 +18,49 @@ __version__ = VERSION
17
18
  _LOGGER = logging.getLogger(__name__)
18
19
 
19
20
 
20
- class Plugin(ABC):
21
+ class ReaderAndWriter:
22
+ def __init__(self, *, output_folder: Union[str, Path], **kwargs: Any) -> None:
23
+ self.output_folder = Path(output_folder)
24
+ self.options = kwargs
25
+
26
+ def read_file(self, path: Union[str, Path]) -> str:
27
+ """How does one read a file in cadl?"""
28
+ # make path relative to output folder
29
+ try:
30
+ with open(self.output_folder / Path(path), "r") as fd:
31
+ return fd.read()
32
+ except FileNotFoundError:
33
+ return ""
34
+
35
+ def write_file(self, filename: Union[str, Path], file_content: str) -> None:
36
+ """How does writing work in cadl?"""
37
+ file_folder = Path(filename).parent
38
+ if not Path.is_dir(self.output_folder / file_folder):
39
+ Path.mkdir(self.output_folder / file_folder, parents=True)
40
+ with open(self.output_folder / Path(filename), "w") as fd:
41
+ fd.write(file_content)
42
+
43
+
44
+ class ReaderAndWriterAutorest(ReaderAndWriter):
45
+ def __init__(
46
+ self, *, output_folder: Union[str, Path], autorestapi: AutorestAPI
47
+ ) -> None:
48
+ super().__init__(output_folder=output_folder)
49
+ self._autorestapi = autorestapi
50
+
51
+ def read_file(self, path: Union[str, Path]) -> str:
52
+ return self._autorestapi.read_file(path)
53
+
54
+ def write_file(self, filename: Union[str, Path], file_content: str) -> None:
55
+ return self._autorestapi.write_file(filename, file_content)
56
+
57
+
58
+ class Plugin(ReaderAndWriter, ABC):
21
59
  """A base class for autorest plugin.
22
60
 
23
61
  :param autorestapi: An autorest API instance
24
62
  """
25
63
 
26
- def __init__(self, autorestapi: AutorestAPI) -> None:
27
- self._autorestapi = autorestapi
28
-
29
64
  @abstractmethod
30
65
  def process(self) -> bool:
31
66
  """The plugin process.
@@ -37,24 +72,41 @@ class Plugin(ABC):
37
72
  raise NotImplementedError()
38
73
 
39
74
 
75
+ class PluginAutorest(Plugin, ReaderAndWriterAutorest):
76
+ """For our Autorest plugins, we want to take autorest api as input as options, then pass it to the Plugin"""
77
+
78
+ def __init__(
79
+ self, autorestapi: AutorestAPI, *, output_folder: Union[str, Path]
80
+ ) -> None:
81
+ super().__init__(autorestapi=autorestapi, output_folder=output_folder)
82
+ self.options = self.get_options()
83
+
84
+ @abstractmethod
85
+ def get_options(self) -> Dict[str, Any]:
86
+ """Get the options bag using the AutorestAPI that we send to the parent plugin"""
87
+
88
+
40
89
  class YamlUpdatePlugin(Plugin):
41
90
  """A plugin that update the YAML as input."""
42
91
 
92
+ def get_yaml(self) -> Dict[str, Any]:
93
+ # cadl file doesn't have to be relative to output folder
94
+ with open(self.options["cadl_file"], "r") as fd:
95
+ return yaml.safe_load(fd.read())
96
+
97
+ def write_yaml(self, yaml_string: str) -> None:
98
+ with open(self.options["cadl_file"], "w") as fd:
99
+ fd.write(yaml_string)
100
+
43
101
  def process(self) -> bool:
44
102
  # List the input file, should be only one
45
- inputs = self._autorestapi.list_inputs()
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)
103
+ yaml_data = self.get_yaml()
52
104
 
53
105
  self.update_yaml(yaml_data)
54
106
 
55
107
  yaml_string = yaml.safe_dump(yaml_data)
56
108
 
57
- self._autorestapi.write_file("code-model-v4-no-tags.yaml", yaml_string)
109
+ self.write_yaml(yaml_string)
58
110
  return True
59
111
 
60
112
  @abstractmethod
@@ -67,4 +119,18 @@ class YamlUpdatePlugin(Plugin):
67
119
  raise NotImplementedError()
68
120
 
69
121
 
70
- __all__ = ["Plugin", "YamlUpdatePlugin"]
122
+ class YamlUpdatePluginAutorest( # pylint: disable=abstract-method
123
+ YamlUpdatePlugin, PluginAutorest
124
+ ):
125
+ def get_yaml(self) -> Dict[str, Any]:
126
+ return yaml.safe_load(self.read_file("code-model-v4-no-tags.yaml"))
127
+
128
+ def write_yaml(self, yaml_string: str) -> None:
129
+ self.write_file("code-model-v4-no-tags.yaml", yaml_string)
130
+
131
+ def get_options(self) -> Dict[str, Any]:
132
+ inputs = self._autorestapi.list_inputs()
133
+ _LOGGER.debug("Possible Inputs: %s", inputs)
134
+ if "code-model-v4-no-tags.yaml" not in inputs:
135
+ raise ValueError("code-model-v4-no-tags.yaml must be a possible input")
136
+ return {}
@@ -0,0 +1,56 @@
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 re
7
+ import argparse
8
+
9
+
10
+ def to_snake_case(name: str) -> str:
11
+ def replace_upper_characters(m) -> str:
12
+ match_str = m.group().lower()
13
+ if m.start() > 0 and name[m.start() - 1] == "_":
14
+ # we are good if a '_' already exists
15
+ return match_str
16
+ # the first letter should not have _
17
+ prefix = "_" if m.start() > 0 else ""
18
+
19
+ # we will add an extra _ if there are multiple upper case chars together
20
+ next_non_upper_case_char_location = m.start() + len(match_str)
21
+ if (
22
+ len(match_str) > 2
23
+ and len(name) - next_non_upper_case_char_location > 1
24
+ and name[next_non_upper_case_char_location].isalpha()
25
+ ):
26
+
27
+ return (
28
+ prefix
29
+ + match_str[: len(match_str) - 1]
30
+ + "_"
31
+ + match_str[len(match_str) - 1]
32
+ )
33
+
34
+ return prefix + match_str
35
+
36
+ return re.sub("[A-Z]+", replace_upper_characters, name)
37
+
38
+
39
+ def parse_args(need_cadl_file: bool = True):
40
+ parser = argparse.ArgumentParser(
41
+ description="Run mypy against target folder. Add a local custom plugin to the path prior to execution. "
42
+ )
43
+ parser.add_argument(
44
+ "--output-folder",
45
+ dest="output_folder",
46
+ help="Output folder for generated SDK",
47
+ required=True,
48
+ )
49
+ parser.add_argument(
50
+ "--cadl-file",
51
+ dest="cadl_file",
52
+ help="Serialized cadl file",
53
+ required=need_cadl_file,
54
+ )
55
+
56
+ return parser.parse_args()
@@ -6,25 +6,27 @@
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
13
+ from .._utils import parse_args
12
14
 
13
- _LOGGER = logging.getLogger(__name__)
15
+ logging.getLogger("blib2to3").setLevel(logging.ERROR)
14
16
 
15
17
  _BLACK_MODE = black.Mode()
16
18
  _BLACK_MODE.line_length = 120
17
19
 
18
20
 
19
- class BlackScriptPlugin(Plugin):
20
- def __init__(self, autorestapi):
21
- super().__init__(autorestapi)
22
- output_folder_uri = self._autorestapi.get_value("outputFolderUri")
23
- if output_folder_uri.startswith("file:"):
24
- output_folder_uri = output_folder_uri[5:]
25
- if os.name == "nt" and output_folder_uri.startswith("///"):
26
- output_folder_uri = output_folder_uri[3:]
27
- self.output_folder = Path(output_folder_uri)
21
+ class BlackScriptPlugin(Plugin): # pylint: disable=abstract-method
22
+ def __init__(self, **kwargs):
23
+ super().__init__(**kwargs)
24
+ output_folder = self.options.get("output_folder", str(self.output_folder))
25
+ if output_folder.startswith("file:"):
26
+ output_folder = output_folder[5:]
27
+ if os.name == "nt" and output_folder.startswith("///"):
28
+ output_folder = output_folder[3:]
29
+ self.output_folder = Path(output_folder)
28
30
 
29
31
  def process(self) -> bool:
30
32
  # apply format_file on every file in the output folder
@@ -38,9 +40,9 @@ class BlackScriptPlugin(Plugin):
38
40
 
39
41
  def format_file(self, full_path) -> None:
40
42
  file = full_path.relative_to(self.output_folder)
41
- file_content = self._autorestapi.read_file(file)
43
+ file_content = self.read_file(file)
42
44
  if not file.suffix == ".py":
43
- self._autorestapi.write_file(file, file_content)
45
+ self.write_file(file, file_content)
44
46
  return
45
47
  try:
46
48
  file_content = black.format_file_contents(
@@ -48,4 +50,15 @@ class BlackScriptPlugin(Plugin):
48
50
  )
49
51
  except black.NothingChanged:
50
52
  pass
51
- self._autorestapi.write_file(file, file_content)
53
+ self.write_file(file, file_content)
54
+
55
+
56
+ class BlackScriptPluginAutorest(BlackScriptPlugin, PluginAutorest):
57
+ def get_options(self) -> Dict[str, Any]:
58
+ return {"output_folder": self._autorestapi.get_value("outputFolderUri")}
59
+
60
+
61
+ if __name__ == "__main__":
62
+ # CADL pipeline will call this
63
+ args = parse_args(need_cadl_file=False)
64
+ BlackScriptPlugin(output_folder=args.output_folder).process()
@@ -4,19 +4,20 @@
4
4
  # license information.
5
5
  # --------------------------------------------------------------------------
6
6
  import logging
7
- import sys
8
7
  from typing import Dict, Any, Union, cast
9
8
  from pathlib import Path
10
9
  import yaml
11
10
 
12
11
 
13
- from .. import Plugin
12
+ from .. import Plugin, PluginAutorest
13
+ from .._utils import parse_args
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
+ from ._utils import DEFAULT_HEADER_TEXT
20
21
 
21
22
 
22
23
  def _build_convenience_layer(yaml_data: Dict[str, Any], code_model: CodeModel) -> None:
@@ -162,8 +163,8 @@ class CodeGenerator(Plugin):
162
163
 
163
164
  def _build_code_model_options(self) -> Dict[str, Any]:
164
165
  """Build en options dict from the user input while running autorest."""
165
- azure_arm = self._autorestapi.get_boolean_value("azure-arm", False)
166
- license_header = self._autorestapi.get_value("header-text")
166
+ azure_arm = self.options.get("azure-arm", False)
167
+ license_header = self.options.get("header-text", DEFAULT_HEADER_TEXT)
167
168
  if license_header:
168
169
  license_header = license_header.replace("\n", "\n# ")
169
170
  license_header = (
@@ -172,83 +173,46 @@ class CodeGenerator(Plugin):
172
173
  )
173
174
  license_header += "\n# --------------------------------------------------------------------------"
174
175
 
175
- low_level_client = cast(
176
- bool, self._autorestapi.get_boolean_value("low-level-client", False)
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
- )
176
+ low_level_client = cast(bool, self.options.get("low-level-client", False))
177
+ version_tolerant = cast(bool, self.options.get("version-tolerant", True))
178
+ show_operations = self.options.get("show-operations", not low_level_client)
184
179
  models_mode_default = (
185
180
  "none" if low_level_client or version_tolerant else "msrest"
186
181
  )
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
182
 
204
183
  options: Dict[str, Any] = {
205
184
  "azure_arm": azure_arm,
206
- "head_as_boolean": self._autorestapi.get_boolean_value(
207
- "head-as-boolean", False
208
- ),
185
+ "head_as_boolean": self.options.get("head-as-boolean", True),
209
186
  "license_header": license_header,
210
- "keep_version_file": self._autorestapi.get_boolean_value(
211
- "keep-version-file", False
212
- ),
213
- "no_async": self._autorestapi.get_boolean_value("no-async", False),
214
- "no_namespace_folders": self._autorestapi.get_boolean_value(
215
- "no-namespace-folders", False
216
- ),
217
- "basic_setup_py": self._autorestapi.get_boolean_value(
218
- "basic-setup-py", False
219
- ),
220
- "package_name": self._autorestapi.get_value("package-name"),
221
- "package_version": self._autorestapi.get_value("package-version"),
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"),
187
+ "keep_version_file": self.options.get("keep-version-file", False),
188
+ "no_async": self.options.get("no-async", False),
189
+ "no_namespace_folders": self.options.get("no-namespace-folders", False),
190
+ "basic_setup_py": self.options.get("basic-setup-py", False),
191
+ "package_name": self.options.get("package-name"),
192
+ "package_version": self.options.get("package-version"),
193
+ "client_side_validation": self.options.get("client-side-validation", False),
194
+ "tracing": self.options.get("tracing", show_operations),
195
+ "multiapi": self.options.get("multiapi", False),
196
+ "polymorphic_examples": self.options.get("polymorphic-examples", 5),
197
+ "models_mode": self.options.get("models-mode", models_mode_default).lower(),
198
+ "builders_visibility": self.options.get("builders-visibility"),
233
199
  "show_operations": show_operations,
234
- "show_send_request": self._autorestapi.get_boolean_value(
200
+ "show_send_request": self.options.get(
235
201
  "show-send-request", low_level_client or version_tolerant
236
202
  ),
237
- "only_path_and_body_params_positional": self._autorestapi.get_boolean_value(
203
+ "only_path_and_body_params_positional": self.options.get(
238
204
  "only-path-and-body-params-positional",
239
205
  low_level_client or version_tolerant,
240
206
  ),
241
207
  "version_tolerant": version_tolerant,
242
208
  "low_level_client": low_level_client,
243
- "combine_operation_files": self._autorestapi.get_boolean_value(
209
+ "combine_operation_files": self.options.get(
244
210
  "combine-operation-files", version_tolerant
245
211
  ),
246
- "package_mode": self._autorestapi.get_value("package-mode"),
247
- "package_pprint_name": self._autorestapi.get_value("package-pprint-name"),
248
- "package_configuration": self._autorestapi.get_value(
249
- "package-configuration"
250
- ),
251
- "default_optional_constants_to_none": self._autorestapi.get_boolean_value(
212
+ "package_mode": self.options.get("package-mode"),
213
+ "package_pprint_name": self.options.get("package-pprint-name"),
214
+ "package_configuration": self.options.get("package-configuration"),
215
+ "default_optional_constants_to_none": self.options.get(
252
216
  "default-optional-constants-to-none",
253
217
  low_level_client or version_tolerant,
254
218
  ),
@@ -272,8 +236,102 @@ class CodeGenerator(Plugin):
272
236
  options["head_as_boolean"] = True
273
237
  return options
274
238
 
239
+ def get_yaml(self) -> Dict[str, Any]:
240
+ # cadl file doesn't have to be relative to output folder
241
+ with open(self.options["cadl_file"], "r") as fd:
242
+ return yaml.safe_load(fd.read())
243
+
244
+ def get_serializer(self, code_model: CodeModel):
245
+ return JinjaSerializer(code_model, output_folder=self.output_folder)
246
+
275
247
  def process(self) -> bool:
276
248
  # List the input file, should be only one
249
+
250
+ options = self._build_code_model_options()
251
+ yaml_data = self.get_yaml()
252
+
253
+ if options["azure_arm"]:
254
+ self.remove_cloud_errors(yaml_data)
255
+
256
+ code_model = self._create_code_model(yaml_data=yaml_data, options=options)
257
+
258
+ serializer = self.get_serializer(code_model)
259
+ serializer.serialize()
260
+
261
+ return True
262
+
263
+
264
+ class CodeGeneratorAutorest(CodeGenerator, PluginAutorest):
265
+ def get_options(self) -> Dict[str, Any]:
266
+ if self._autorestapi.get_boolean_value("python3-only") is False:
267
+ _LOGGER.warning(
268
+ "You have passed in --python3-only=False. We have force overriden "
269
+ "this to True."
270
+ )
271
+ if self._autorestapi.get_boolean_value("add-python3-operation-files"):
272
+ _LOGGER.warning(
273
+ "You have passed in --add-python3-operation-files. "
274
+ "This flag no longer has an effect bc all SDKs are now Python3 only."
275
+ )
276
+ if self._autorestapi.get_boolean_value("reformat-next-link"):
277
+ _LOGGER.warning(
278
+ "You have passed in --reformat-next-link. We have force overriden "
279
+ "this to False because we no longer reformat initial query parameters into next "
280
+ "calls unless explicitly defined in the service definition."
281
+ )
282
+ options = {
283
+ "azure-arm": self._autorestapi.get_boolean_value("azure-arm"),
284
+ "header-text": self._autorestapi.get_value("header-text"),
285
+ "low-level-client": self._autorestapi.get_boolean_value(
286
+ "low-level-client", False
287
+ ),
288
+ "version-tolerant": self._autorestapi.get_boolean_value(
289
+ "version-tolerant", True
290
+ ),
291
+ "show-operations": self._autorestapi.get_boolean_value("show-operations"),
292
+ "python3-only": self._autorestapi.get_boolean_value("python3-only"),
293
+ "head-as-boolean": self._autorestapi.get_boolean_value(
294
+ "head-as-boolean", False
295
+ ),
296
+ "keep-version-file": self._autorestapi.get_boolean_value(
297
+ "keep-version-file"
298
+ ),
299
+ "no-async": self._autorestapi.get_boolean_value("no-async"),
300
+ "no-namespace-folders": self._autorestapi.get_boolean_value(
301
+ "no-namespace-folders"
302
+ ),
303
+ "basic-setup-py": self._autorestapi.get_boolean_value("basic-setup-py"),
304
+ "package-name": self._autorestapi.get_value("package-name"),
305
+ "package-version": self._autorestapi.get_value("package-version"),
306
+ "client-side-validation": self._autorestapi.get_boolean_value(
307
+ "client-side-validation"
308
+ ),
309
+ "tracing": self._autorestapi.get_boolean_value("trace"),
310
+ "multiapi": self._autorestapi.get_boolean_value("multiapi", False),
311
+ "polymorphic-examples": self._autorestapi.get_value("polymorphic-examples"),
312
+ "models-mode": self._autorestapi.get_value("models-mode"),
313
+ "builders-visibility": self._autorestapi.get_value("builders-visibility"),
314
+ "show-send-request": self._autorestapi.get_boolean_value(
315
+ "show-send-request"
316
+ ),
317
+ "only-path-and-body-params-positional": self._autorestapi.get_boolean_value(
318
+ "only-path-and-body-params-positional"
319
+ ),
320
+ "combine-operation-files": self._autorestapi.get_boolean_value(
321
+ "combine-operation-files"
322
+ ),
323
+ "package-mode": self._autorestapi.get_value("package-mode"),
324
+ "package-pprint-name": self._autorestapi.get_value("package-pprint-name"),
325
+ "package-configuration": self._autorestapi.get_value(
326
+ "package-configuration"
327
+ ),
328
+ "default-optional-constants-to-none": self._autorestapi.get_boolean_value(
329
+ "default-optional-constants-to-none"
330
+ ),
331
+ }
332
+ return {k: v for k, v in options.items() if v is not None}
333
+
334
+ def get_yaml(self) -> Dict[str, Any]:
277
335
  inputs = self._autorestapi.list_inputs()
278
336
  _LOGGER.debug("Possible Inputs: %s", inputs)
279
337
  if "code-model-v4-no-tags.yaml" not in inputs:
@@ -291,32 +349,15 @@ class CodeGenerator(Plugin):
291
349
  file_content = self._autorestapi.read_file("code-model-v4-no-tags.yaml")
292
350
 
293
351
  # Parse the received YAML
294
- yaml_data = yaml.safe_load(file_content)
295
-
296
- options = self._build_code_model_options()
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()
352
+ return yaml.safe_load(file_content)
305
353
 
306
- return True
307
-
308
-
309
- def main(yaml_model_file: str) -> None:
310
- from ..jsonrpc.localapi import ( # pylint: disable=import-outside-toplevel
311
- LocalAutorestAPI,
312
- )
313
-
314
- code_generator = CodeGenerator(
315
- autorestapi=LocalAutorestAPI(reachable_files=[yaml_model_file])
316
- )
317
- if not code_generator.process():
318
- raise SystemExit("Process didn't finish gracefully")
354
+ def get_serializer(self, code_model: CodeModel): # type: ignore
355
+ return JinjaSerializerAutorest(
356
+ self._autorestapi, code_model, output_folder=self.output_folder
357
+ )
319
358
 
320
359
 
321
360
  if __name__ == "__main__":
322
- main(sys.argv[1])
361
+ # CADL pipeline will call this
362
+ args = parse_args()
363
+ CodeGenerator(output_folder=args.output_folder, cadl_file=args.cadl_file).process()
@@ -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
+
7
+ DEFAULT_HEADER_TEXT = (
8
+ "# --------------------------------------------------------------------------\n"
9
+ "# Copyright (c) Microsoft Corporation. All rights reserved.\n"
10
+ "# Licensed under the MIT License. See License.txt in the project root for license information.\n"
11
+ "# Code generated by Microsoft (R) Python Code Generator.\n"
12
+ "# Changes may cause incorrect behavior and will be lost if the code is regenerated.\n"
13
+ "# --------------------------------------------------------------------------"
14
+ )