@typespec/http-client-python 0.14.1 → 0.14.3-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/emitter/emitter.js +1 -3
- package/dist/emitter/emitter.js.map +1 -1
- package/dist/emitter/lib.d.ts +1 -0
- package/dist/emitter/lib.d.ts.map +1 -1
- package/dist/emitter/lib.js +10 -0
- package/dist/emitter/lib.js.map +1 -1
- package/emitter/src/emitter.ts +1 -3
- package/emitter/src/lib.ts +13 -0
- package/emitter/temp/tsconfig.tsbuildinfo +1 -1
- package/eng/scripts/ci/regenerate.ts +11 -4
- package/eng/scripts/setup/__pycache__/package_manager.cpython-39.pyc +0 -0
- package/eng/scripts/setup/__pycache__/venvtools.cpython-39.pyc +0 -0
- package/generator/build/lib/pygen/__init__.py +19 -1
- package/generator/build/lib/pygen/codegen/models/code_model.py +32 -0
- package/generator/build/lib/pygen/codegen/models/operation.py +3 -4
- package/generator/build/lib/pygen/codegen/models/paging_operation.py +1 -1
- package/generator/build/lib/pygen/codegen/serializers/__init__.py +79 -71
- package/generator/build/lib/pygen/codegen/serializers/builder_serializer.py +4 -3
- package/generator/build/lib/pygen/codegen/serializers/general_serializer.py +86 -13
- package/generator/build/lib/pygen/codegen/serializers/model_serializer.py +1 -1
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/pyproject.toml.jinja2 +109 -0
- package/generator/component-detection-pip-report.json +1 -1
- package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
- package/generator/pygen/__init__.py +19 -1
- package/generator/pygen/codegen/models/code_model.py +32 -0
- package/generator/pygen/codegen/models/operation.py +3 -4
- package/generator/pygen/codegen/models/paging_operation.py +1 -1
- package/generator/pygen/codegen/serializers/__init__.py +79 -71
- package/generator/pygen/codegen/serializers/builder_serializer.py +4 -3
- package/generator/pygen/codegen/serializers/general_serializer.py +86 -13
- package/generator/pygen/codegen/serializers/model_serializer.py +1 -1
- package/generator/pygen/codegen/templates/packaging_templates/pyproject.toml.jinja2 +109 -0
- package/generator/pygen.egg-info/SOURCES.txt +1 -0
- package/generator/test/azure/requirements.txt +1 -0
- package/generator/test/azure/tox.ini +2 -2
- package/generator/test/generic_mock_api_tests/asynctests/test_authentication_async.py +7 -4
- package/generator/test/generic_mock_api_tests/test_authentication.py +7 -4
- package/generator/test/unbranded/mock_api_tests/test_unbranded.py +3 -1
- package/generator/test/unbranded/requirements.txt +1 -0
- package/generator/test/unbranded/tox.ini +2 -2
- package/package.json +1 -1
|
Binary file
|
|
Binary file
|
|
@@ -25,10 +25,10 @@ class OptionsDict(MutableMapping):
|
|
|
25
25
|
"azure-arm": False,
|
|
26
26
|
"basic-setup-py": False,
|
|
27
27
|
"client-side-validation": False,
|
|
28
|
-
"emit-cross-language-definition-file": False,
|
|
29
28
|
"flavor": "azure", # need to default to azure in shared code so we don't break swagger generation
|
|
30
29
|
"from-typespec": False,
|
|
31
30
|
"generate-sample": False,
|
|
31
|
+
"keep-setup-py": False,
|
|
32
32
|
"generate-test": False,
|
|
33
33
|
"head-as-boolean": True,
|
|
34
34
|
"keep-version-file": False,
|
|
@@ -39,6 +39,7 @@ class OptionsDict(MutableMapping):
|
|
|
39
39
|
"polymorphic-examples": 5,
|
|
40
40
|
"validate-versioning": True,
|
|
41
41
|
"version-tolerant": True,
|
|
42
|
+
"generation-subdir": None, # subdirectory to generate the code in
|
|
42
43
|
}
|
|
43
44
|
|
|
44
45
|
def __init__(self, options: Optional[Dict[str, Any]] = None) -> None:
|
|
@@ -106,6 +107,8 @@ class OptionsDict(MutableMapping):
|
|
|
106
107
|
models_mode_default = "dpg"
|
|
107
108
|
# switch to falsy value for easier code writing
|
|
108
109
|
return models_mode_default
|
|
110
|
+
if key == "emit-cross-language-definition-file":
|
|
111
|
+
return self.get("flavor") == "azure"
|
|
109
112
|
return self.DEFAULTS[key]
|
|
110
113
|
|
|
111
114
|
def _validate_combinations(self) -> None:
|
|
@@ -134,6 +137,10 @@ class OptionsDict(MutableMapping):
|
|
|
134
137
|
"We are working on creating a new multiapi SDK for version tolerant and it is not available yet."
|
|
135
138
|
)
|
|
136
139
|
|
|
140
|
+
# If multiapi, do not generate default pyproject.toml
|
|
141
|
+
if self.get("multiapi"):
|
|
142
|
+
self["keep-setup-py"] = True
|
|
143
|
+
|
|
137
144
|
if self.get("client-side-validation") and self.get("version-tolerant"):
|
|
138
145
|
raise ValueError("Can not generate version tolerant with --client-side-validation. ")
|
|
139
146
|
|
|
@@ -210,6 +217,9 @@ class ReaderAndWriter:
|
|
|
210
217
|
_LOGGER.warning("Loading python.json file. This behavior will be depreacted")
|
|
211
218
|
self.options.update(python_json)
|
|
212
219
|
|
|
220
|
+
def get_output_folder(self) -> Path:
|
|
221
|
+
return self.output_folder
|
|
222
|
+
|
|
213
223
|
def read_file(self, path: Union[str, Path]) -> str:
|
|
214
224
|
"""Directly reading from disk"""
|
|
215
225
|
# make path relative to output folder
|
|
@@ -227,6 +237,14 @@ class ReaderAndWriter:
|
|
|
227
237
|
with open(self.output_folder / Path(filename), "w", encoding="utf-8") as fd:
|
|
228
238
|
fd.write(file_content)
|
|
229
239
|
|
|
240
|
+
def remove_file(self, filename: Union[str, Path]) -> None:
|
|
241
|
+
try:
|
|
242
|
+
file_path = self.output_folder / Path(filename)
|
|
243
|
+
if file_path.is_file():
|
|
244
|
+
file_path.unlink()
|
|
245
|
+
except FileNotFoundError:
|
|
246
|
+
pass
|
|
247
|
+
|
|
230
248
|
def list_file(self) -> List[str]:
|
|
231
249
|
return [str(f.relative_to(self.output_folder)) for f in self.output_folder.glob("**/*") if f.is_file()]
|
|
232
250
|
|
|
@@ -3,6 +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 pathlib import Path
|
|
6
7
|
from typing import List, Dict, Any, Set, Union, Literal, Optional, cast
|
|
7
8
|
|
|
8
9
|
from .base import BaseType
|
|
@@ -452,3 +453,34 @@ class CodeModel: # pylint: disable=too-many-public-methods, disable=too-many-in
|
|
|
452
453
|
return self.yaml_data.get("licenseInfo", {}).get("company", "")
|
|
453
454
|
# typespec azure case without custom license and swagger case
|
|
454
455
|
return "Microsoft Corporation"
|
|
456
|
+
|
|
457
|
+
def get_root_dir(self) -> Path:
|
|
458
|
+
if self.options["no-namespace-folders"]:
|
|
459
|
+
# when output folder contains parts different from the namespace, we fall back to current folder directly.
|
|
460
|
+
return Path(".")
|
|
461
|
+
return Path(*self.namespace.split("."))
|
|
462
|
+
|
|
463
|
+
def get_generation_dir(self, namespace: str) -> Path:
|
|
464
|
+
"""The directory to generate the code in.
|
|
465
|
+
|
|
466
|
+
If 'generation-subdir' is specified, it will be used as a subdirectory.
|
|
467
|
+
"""
|
|
468
|
+
root_dir = self.get_root_dir()
|
|
469
|
+
retval = self._get_relative_generation_dir(root_dir, namespace)
|
|
470
|
+
return retval
|
|
471
|
+
|
|
472
|
+
def _get_relative_generation_dir(self, root_dir: Path, namespace: str) -> Path:
|
|
473
|
+
if self.options["no-namespace-folders"]:
|
|
474
|
+
return Path(".")
|
|
475
|
+
if self.options.get("generation-subdir"):
|
|
476
|
+
# For the main namespace, return root_dir + generation-subdir
|
|
477
|
+
if namespace in ("", self.namespace):
|
|
478
|
+
return root_dir / self.options["generation-subdir"]
|
|
479
|
+
|
|
480
|
+
# For subnamespaces, extract the subnamespace part and append it to generation-subdir
|
|
481
|
+
if namespace.startswith(self.namespace + "."):
|
|
482
|
+
subnamespace_parts = namespace[len(self.namespace) + 1 :].split(".")
|
|
483
|
+
return root_dir / self.options["generation-subdir"] / Path(*subnamespace_parts)
|
|
484
|
+
|
|
485
|
+
# No generation-subdir specified, use the namespace path directly
|
|
486
|
+
return Path(*namespace.split("."))
|
|
@@ -194,14 +194,13 @@ class OperationBase( # pylint: disable=too-many-public-methods,too-many-instanc
|
|
|
194
194
|
def any_response_has_headers(self) -> bool:
|
|
195
195
|
return any(response.headers for response in self.responses)
|
|
196
196
|
|
|
197
|
-
|
|
198
|
-
def default_error_deserialization(self) -> Optional[str]:
|
|
197
|
+
def default_error_deserialization(self, serialize_namespace: str) -> Optional[str]:
|
|
199
198
|
default_exceptions = [e for e in self.exceptions if "default" in e.status_codes and e.type]
|
|
200
199
|
if not default_exceptions:
|
|
201
200
|
return None
|
|
202
201
|
exception_schema = default_exceptions[0].type
|
|
203
202
|
if isinstance(exception_schema, ModelType):
|
|
204
|
-
return exception_schema.type_annotation(skip_quote=True)
|
|
203
|
+
return exception_schema.type_annotation(skip_quote=True, serialize_namespace=serialize_namespace)
|
|
205
204
|
return None if self.code_model.options["models-mode"] == "dpg" else "'object'"
|
|
206
205
|
|
|
207
206
|
@property
|
|
@@ -469,7 +468,7 @@ class OperationBase( # pylint: disable=too-many-public-methods,too-many-instanc
|
|
|
469
468
|
file_import.add_submodule_import(relative_path, "_deserialize_xml", ImportType.LOCAL)
|
|
470
469
|
elif self.need_deserialize:
|
|
471
470
|
file_import.add_submodule_import(relative_path, "_deserialize", ImportType.LOCAL)
|
|
472
|
-
if self.default_error_deserialization or self.non_default_errors:
|
|
471
|
+
if self.default_error_deserialization(serialize_namespace) or self.non_default_errors:
|
|
473
472
|
file_import.add_submodule_import(relative_path, "_failsafe_deserialize", ImportType.LOCAL)
|
|
474
473
|
return file_import
|
|
475
474
|
|
|
@@ -173,7 +173,7 @@ class PagingOperationBase(OperationBase[PagingResponseType]):
|
|
|
173
173
|
serialize_namespace, module_name="_utils.model_base"
|
|
174
174
|
)
|
|
175
175
|
file_import.merge(self.item_type.imports(**kwargs))
|
|
176
|
-
if self.default_error_deserialization or self.need_deserialize:
|
|
176
|
+
if self.default_error_deserialization(serialize_namespace) or self.need_deserialize:
|
|
177
177
|
file_import.add_submodule_import(relative_path, "_deserialize", ImportType.LOCAL)
|
|
178
178
|
return file_import
|
|
179
179
|
|
|
@@ -9,6 +9,7 @@ from collections import namedtuple
|
|
|
9
9
|
import re
|
|
10
10
|
from typing import List, Any, Union
|
|
11
11
|
from pathlib import Path
|
|
12
|
+
from packaging.version import parse as parse_version
|
|
12
13
|
from jinja2 import PackageLoader, Environment, FileSystemLoader, StrictUndefined
|
|
13
14
|
|
|
14
15
|
from ... import ReaderAndWriter
|
|
@@ -52,10 +53,9 @@ _PACKAGE_FILES = [
|
|
|
52
53
|
"LICENSE.jinja2",
|
|
53
54
|
"MANIFEST.in.jinja2",
|
|
54
55
|
"README.md.jinja2",
|
|
55
|
-
"setup.py.jinja2",
|
|
56
56
|
]
|
|
57
57
|
|
|
58
|
-
_REGENERATE_FILES = {"
|
|
58
|
+
_REGENERATE_FILES = {"MANIFEST.in"}
|
|
59
59
|
AsyncInfo = namedtuple("AsyncInfo", ["async_mode", "async_path"])
|
|
60
60
|
|
|
61
61
|
|
|
@@ -80,6 +80,15 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
80
80
|
) -> None:
|
|
81
81
|
super().__init__(output_folder=output_folder, **kwargs)
|
|
82
82
|
self.code_model = code_model
|
|
83
|
+
self._regenerate_setup_py()
|
|
84
|
+
|
|
85
|
+
def _regenerate_setup_py(self):
|
|
86
|
+
if self.code_model.options["keep-setup-py"] or self.code_model.options["basic-setup-py"]:
|
|
87
|
+
_PACKAGE_FILES.append("setup.py.jinja2")
|
|
88
|
+
_REGENERATE_FILES.add("setup.py")
|
|
89
|
+
else:
|
|
90
|
+
_PACKAGE_FILES.append("pyproject.toml.jinja2")
|
|
91
|
+
_REGENERATE_FILES.add("pyproject.toml")
|
|
83
92
|
|
|
84
93
|
@property
|
|
85
94
|
def has_aio_folder(self) -> bool:
|
|
@@ -101,12 +110,18 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
101
110
|
return True
|
|
102
111
|
# If the version file is already there and the version is greater than the current version, keep it.
|
|
103
112
|
try:
|
|
104
|
-
serialized_version_file = self.read_file(
|
|
113
|
+
serialized_version_file = self.read_file(
|
|
114
|
+
self.code_model.get_generation_dir(self.code_model.namespace) / "_version.py"
|
|
115
|
+
)
|
|
105
116
|
match = re.search(r'VERSION\s*=\s*"([^"]+)"', str(serialized_version_file))
|
|
106
117
|
serialized_version = match.group(1) if match else ""
|
|
107
118
|
except (FileNotFoundError, IndexError):
|
|
108
119
|
serialized_version = ""
|
|
109
|
-
|
|
120
|
+
try:
|
|
121
|
+
return parse_version(serialized_version) > parse_version(self.code_model.options.get("package-version", ""))
|
|
122
|
+
except Exception: # pylint: disable=broad-except
|
|
123
|
+
# If parsing the version fails, we assume the version file is not valid and overwrite.
|
|
124
|
+
return False
|
|
110
125
|
|
|
111
126
|
def serialize(self) -> None:
|
|
112
127
|
env = Environment(
|
|
@@ -120,34 +135,37 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
120
135
|
|
|
121
136
|
general_serializer = GeneralSerializer(code_model=self.code_model, env=env, async_mode=False)
|
|
122
137
|
for client_namespace, client_namespace_type in self.code_model.client_namespace_types.items():
|
|
123
|
-
|
|
138
|
+
generation_path = self.code_model.get_generation_dir(client_namespace)
|
|
124
139
|
if client_namespace == "":
|
|
125
|
-
# Write the setup file
|
|
126
140
|
if self.code_model.options["basic-setup-py"]:
|
|
127
|
-
|
|
141
|
+
# Write the setup file
|
|
142
|
+
self.write_file(generation_path / Path("setup.py"), general_serializer.serialize_setup_file())
|
|
143
|
+
elif not self.code_model.options["keep-setup-py"]:
|
|
144
|
+
# remove setup.py file
|
|
145
|
+
self.remove_file(generation_path / Path("setup.py"))
|
|
128
146
|
|
|
129
147
|
# add packaging files in root namespace (e.g. setup.py, README.md, etc.)
|
|
130
148
|
if self.code_model.options.get("package-mode"):
|
|
131
|
-
self._serialize_and_write_package_files(
|
|
149
|
+
self._serialize_and_write_package_files()
|
|
132
150
|
|
|
133
151
|
# write apiview-properties.json
|
|
134
152
|
if self.code_model.options.get("emit-cross-language-definition-file"):
|
|
135
153
|
self.write_file(
|
|
136
|
-
|
|
154
|
+
generation_path / Path("apiview-properties.json"),
|
|
137
155
|
general_serializer.serialize_cross_language_definition_file(),
|
|
138
156
|
)
|
|
139
157
|
|
|
140
158
|
# add generated samples and generated tests
|
|
141
159
|
if self.code_model.options["show-operations"] and self.code_model.has_operations:
|
|
142
160
|
if self.code_model.options["generate-sample"]:
|
|
143
|
-
self._serialize_and_write_sample(env
|
|
161
|
+
self._serialize_and_write_sample(env)
|
|
144
162
|
if self.code_model.options["generate-test"]:
|
|
145
|
-
self._serialize_and_write_test(env
|
|
163
|
+
self._serialize_and_write_test(env)
|
|
146
164
|
|
|
147
165
|
# add _metadata.json
|
|
148
166
|
if self.code_model.metadata:
|
|
149
167
|
self.write_file(
|
|
150
|
-
|
|
168
|
+
generation_path / Path("_metadata.json"),
|
|
151
169
|
json.dumps(self.code_model.metadata, indent=2),
|
|
152
170
|
)
|
|
153
171
|
elif client_namespace_type.clients:
|
|
@@ -156,7 +174,7 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
156
174
|
else:
|
|
157
175
|
# add pkgutil init file if no clients in this namespace
|
|
158
176
|
self.write_file(
|
|
159
|
-
|
|
177
|
+
generation_path / Path("__init__.py"),
|
|
160
178
|
general_serializer.serialize_pkgutil_init_file(),
|
|
161
179
|
)
|
|
162
180
|
|
|
@@ -178,7 +196,7 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
178
196
|
|
|
179
197
|
if not self.code_model.options["models-mode"]:
|
|
180
198
|
# keep models file if users ended up just writing a models file
|
|
181
|
-
model_path =
|
|
199
|
+
model_path = generation_path / Path("models.py")
|
|
182
200
|
if self.read_file(model_path):
|
|
183
201
|
self.write_file(model_path, self.read_file(model_path))
|
|
184
202
|
|
|
@@ -194,12 +212,15 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
194
212
|
# to make sure all generated files could be packed into .zip/.whl/.tgz package
|
|
195
213
|
if not client_namespace_type.clients and client_namespace_type.operation_groups and self.has_aio_folder:
|
|
196
214
|
self.write_file(
|
|
197
|
-
|
|
215
|
+
generation_path / Path("aio/__init__.py"),
|
|
198
216
|
general_serializer.serialize_pkgutil_init_file(),
|
|
199
217
|
)
|
|
200
218
|
|
|
201
|
-
def _serialize_and_write_package_files(self
|
|
202
|
-
root_of_sdk =
|
|
219
|
+
def _serialize_and_write_package_files(self) -> None:
|
|
220
|
+
root_of_sdk = Path(".")
|
|
221
|
+
if self.code_model.options["no-namespace-folders"]:
|
|
222
|
+
compensation = Path("../" * (self.code_model.namespace.count(".") + 1))
|
|
223
|
+
root_of_sdk = root_of_sdk / compensation
|
|
203
224
|
if self.code_model.options["package-mode"] in VALID_PACKAGE_MODE:
|
|
204
225
|
env = Environment(
|
|
205
226
|
loader=PackageLoader("pygen.codegen", "templates/packaging_templates"),
|
|
@@ -228,12 +249,13 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
228
249
|
file = template_name.replace(".jinja2", "")
|
|
229
250
|
output_name = root_of_sdk / file
|
|
230
251
|
if not self.read_file(output_name) or file in _REGENERATE_FILES:
|
|
231
|
-
if self.keep_version_file and file == "setup.py":
|
|
232
|
-
# don't regenerate setup.py file if the version file is more up to date
|
|
252
|
+
if self.keep_version_file and file == "setup.py" and not self.code_model.options["azure-arm"]:
|
|
253
|
+
# don't regenerate setup.py file if the version file is more up to date for data-plane
|
|
233
254
|
continue
|
|
255
|
+
file_path = self.get_output_folder() / Path(output_name)
|
|
234
256
|
self.write_file(
|
|
235
257
|
output_name,
|
|
236
|
-
serializer.serialize_package_file(template_name, **params),
|
|
258
|
+
serializer.serialize_package_file(template_name, file_path, **params),
|
|
237
259
|
)
|
|
238
260
|
|
|
239
261
|
def _keep_patch_file(self, path_file: Path, env: Environment):
|
|
@@ -249,7 +271,7 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
249
271
|
self, env: Environment, namespace: str, models: List[ModelType], enums: List[EnumType]
|
|
250
272
|
) -> None:
|
|
251
273
|
# Write the models folder
|
|
252
|
-
models_path = self.
|
|
274
|
+
models_path = self.code_model.get_generation_dir(namespace) / "models"
|
|
253
275
|
serializer = DpgModelSerializer if self.code_model.options["models-mode"] == "dpg" else MsrestModelSerializer
|
|
254
276
|
if self.code_model.has_non_json_models(models):
|
|
255
277
|
self.write_file(
|
|
@@ -317,7 +339,7 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
317
339
|
self, operation_groups: List[OperationGroup], env: Environment, namespace: str
|
|
318
340
|
) -> None:
|
|
319
341
|
operations_folder_name = self.code_model.operations_folder_name(namespace)
|
|
320
|
-
|
|
342
|
+
generation_path = self.code_model.get_generation_dir(namespace)
|
|
321
343
|
for async_mode, async_path in self.serialize_loop:
|
|
322
344
|
prefix_path = f"{async_path}{operations_folder_name}"
|
|
323
345
|
# write init file
|
|
@@ -325,7 +347,7 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
325
347
|
code_model=self.code_model, operation_groups=operation_groups, env=env, async_mode=async_mode
|
|
326
348
|
)
|
|
327
349
|
self.write_file(
|
|
328
|
-
|
|
350
|
+
generation_path / Path(f"{prefix_path}/__init__.py"),
|
|
329
351
|
operations_init_serializer.serialize(),
|
|
330
352
|
)
|
|
331
353
|
|
|
@@ -344,26 +366,25 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
344
366
|
client_namespace=namespace,
|
|
345
367
|
)
|
|
346
368
|
self.write_file(
|
|
347
|
-
|
|
369
|
+
generation_path / Path(f"{prefix_path}/{filename}.py"),
|
|
348
370
|
operation_group_serializer.serialize(),
|
|
349
371
|
)
|
|
350
372
|
|
|
351
373
|
# if there was a patch file before, we keep it
|
|
352
|
-
self._keep_patch_file(
|
|
374
|
+
self._keep_patch_file(generation_path / Path(f"{prefix_path}/_patch.py"), env)
|
|
353
375
|
|
|
354
376
|
def _serialize_and_write_version_file(
|
|
355
377
|
self,
|
|
356
|
-
namespace: str,
|
|
357
378
|
general_serializer: GeneralSerializer,
|
|
358
379
|
):
|
|
359
|
-
|
|
380
|
+
generation_path = self.code_model.get_root_dir()
|
|
360
381
|
|
|
361
382
|
def _read_version_file(original_version_file_name: str) -> str:
|
|
362
|
-
return self.read_file(
|
|
383
|
+
return self.read_file(generation_path / original_version_file_name)
|
|
363
384
|
|
|
364
385
|
def _write_version_file(original_version_file_name: str) -> None:
|
|
365
386
|
self.write_file(
|
|
366
|
-
|
|
387
|
+
generation_path / Path("_version.py"),
|
|
367
388
|
_read_version_file(original_version_file_name),
|
|
368
389
|
)
|
|
369
390
|
|
|
@@ -373,7 +394,7 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
373
394
|
_write_version_file(original_version_file_name="version.py")
|
|
374
395
|
elif self.code_model.options.get("package-version"):
|
|
375
396
|
self.write_file(
|
|
376
|
-
|
|
397
|
+
generation_path / Path("_version.py"),
|
|
377
398
|
general_serializer.serialize_version_file(),
|
|
378
399
|
)
|
|
379
400
|
|
|
@@ -383,47 +404,47 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
383
404
|
clients: List[Client],
|
|
384
405
|
env: Environment,
|
|
385
406
|
) -> None:
|
|
386
|
-
|
|
407
|
+
generation_path = self.code_model.get_generation_dir(namespace)
|
|
387
408
|
for async_mode, async_path in self.serialize_loop:
|
|
388
409
|
general_serializer = GeneralSerializer(
|
|
389
410
|
code_model=self.code_model, env=env, async_mode=async_mode, client_namespace=namespace
|
|
390
411
|
)
|
|
391
412
|
# when there is client.py, there must be __init__.py
|
|
392
413
|
self.write_file(
|
|
393
|
-
|
|
414
|
+
generation_path / Path(f"{async_path}__init__.py"),
|
|
394
415
|
general_serializer.serialize_init_file([c for c in clients if c.has_operations]),
|
|
395
416
|
)
|
|
396
417
|
|
|
397
418
|
# if there was a patch file before, we keep it
|
|
398
|
-
self._keep_patch_file(
|
|
419
|
+
self._keep_patch_file(generation_path / Path(f"{async_path}_patch.py"), env)
|
|
399
420
|
|
|
400
421
|
if self.code_model.clients_has_operations(clients):
|
|
401
422
|
|
|
402
423
|
# write client file
|
|
403
424
|
self.write_file(
|
|
404
|
-
|
|
425
|
+
generation_path / Path(f"{async_path}{self.code_model.client_filename}.py"),
|
|
405
426
|
general_serializer.serialize_service_client_file(clients),
|
|
406
427
|
)
|
|
407
428
|
|
|
408
429
|
# write config file
|
|
409
430
|
self.write_file(
|
|
410
|
-
|
|
431
|
+
generation_path / Path(f"{async_path}_configuration.py"),
|
|
411
432
|
general_serializer.serialize_config_file(clients),
|
|
412
433
|
)
|
|
413
434
|
|
|
414
435
|
# sometimes we need define additional Mixin class for client in _utils.py
|
|
415
436
|
self._serialize_and_write_utils_folder(env, namespace)
|
|
416
437
|
|
|
417
|
-
def _serialize_and_write_utils_folder(self, env: Environment, namespace: str)
|
|
418
|
-
|
|
438
|
+
def _serialize_and_write_utils_folder(self, env: Environment, namespace: str):
|
|
439
|
+
generation_dir = self.code_model.get_generation_dir(namespace)
|
|
419
440
|
general_serializer = GeneralSerializer(code_model=self.code_model, env=env, async_mode=False)
|
|
420
|
-
utils_folder_path =
|
|
421
|
-
if self.code_model.need_utils_folder(async_mode=False, client_namespace=namespace):
|
|
441
|
+
utils_folder_path = generation_dir / Path("_utils")
|
|
442
|
+
if self.code_model.need_utils_folder(async_mode=False, client_namespace=self.code_model.namespace):
|
|
422
443
|
self.write_file(
|
|
423
444
|
utils_folder_path / Path("__init__.py"),
|
|
424
445
|
self.code_model.license_header,
|
|
425
446
|
)
|
|
426
|
-
if self.code_model.need_utils_utils(async_mode=False, client_namespace=namespace):
|
|
447
|
+
if self.code_model.need_utils_utils(async_mode=False, client_namespace=self.code_model.namespace):
|
|
427
448
|
self.write_file(
|
|
428
449
|
utils_folder_path / Path("utils.py"),
|
|
429
450
|
general_serializer.need_utils_utils_file(),
|
|
@@ -443,56 +464,43 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
443
464
|
)
|
|
444
465
|
|
|
445
466
|
def _serialize_and_write_top_level_folder(self, env: Environment, namespace: str) -> None:
|
|
446
|
-
|
|
467
|
+
root_dir = self.code_model.get_root_dir()
|
|
447
468
|
# write _utils folder
|
|
448
|
-
self._serialize_and_write_utils_folder(env, namespace)
|
|
469
|
+
self._serialize_and_write_utils_folder(env, self.code_model.namespace)
|
|
449
470
|
|
|
450
471
|
general_serializer = GeneralSerializer(code_model=self.code_model, env=env, async_mode=False)
|
|
451
472
|
|
|
452
473
|
# write _version.py
|
|
453
|
-
self._serialize_and_write_version_file(
|
|
474
|
+
self._serialize_and_write_version_file(general_serializer)
|
|
454
475
|
|
|
455
476
|
# write the empty py.typed file
|
|
456
|
-
|
|
477
|
+
pytyped_value = "# Marker file for PEP 561."
|
|
478
|
+
# TODO: remove this when we remove legacy multiapi generation
|
|
479
|
+
if self.code_model.options["multiapi"]:
|
|
480
|
+
self.write_file(self.code_model.get_generation_dir(namespace) / Path("py.typed"), pytyped_value)
|
|
481
|
+
else:
|
|
482
|
+
self.write_file(root_dir / Path("py.typed"), pytyped_value)
|
|
457
483
|
|
|
458
484
|
# write _validation.py
|
|
459
485
|
if any(og for client in self.code_model.clients for og in client.operation_groups if og.need_validation):
|
|
460
486
|
self.write_file(
|
|
461
|
-
|
|
487
|
+
root_dir / Path("_validation.py"),
|
|
462
488
|
general_serializer.serialize_validation_file(),
|
|
463
489
|
)
|
|
464
490
|
|
|
465
491
|
# write _types.py
|
|
466
492
|
if self.code_model.named_unions:
|
|
467
493
|
self.write_file(
|
|
468
|
-
|
|
494
|
+
root_dir / Path("_types.py"),
|
|
469
495
|
TypesSerializer(code_model=self.code_model, env=env).serialize(),
|
|
470
496
|
)
|
|
471
497
|
|
|
472
498
|
def _serialize_and_write_metadata(self, env: Environment, namespace: str) -> None:
|
|
473
|
-
metadata_serializer = MetadataSerializer(self.code_model, env
|
|
474
|
-
self.write_file(
|
|
475
|
-
|
|
476
|
-
@property
|
|
477
|
-
def exec_path_compensation(self) -> Path:
|
|
478
|
-
"""Assume the process is running in the root folder of the package. If not, we need the path compensation."""
|
|
479
|
-
return (
|
|
480
|
-
Path("../" * (self.code_model.namespace.count(".") + 1))
|
|
481
|
-
if self.code_model.options["no-namespace-folders"]
|
|
482
|
-
else Path(".")
|
|
499
|
+
metadata_serializer = MetadataSerializer(self.code_model, env)
|
|
500
|
+
self.write_file(
|
|
501
|
+
self.code_model.get_generation_dir(namespace) / Path("_metadata.json"), metadata_serializer.serialize()
|
|
483
502
|
)
|
|
484
503
|
|
|
485
|
-
def exec_path_for_test_sample(self, namespace: str) -> Path:
|
|
486
|
-
return self.exec_path_compensation / Path(*namespace.split("."))
|
|
487
|
-
|
|
488
|
-
# pylint: disable=line-too-long
|
|
489
|
-
def exec_path(self, namespace: str) -> Path:
|
|
490
|
-
if self.code_model.options["no-namespace-folders"] and not self.code_model.options["multiapi"]:
|
|
491
|
-
# when output folder contains parts different from the namespace, we fall back to current folder directly.
|
|
492
|
-
# (e.g. https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/communication/azure-communication-callautomation/swagger/SWAGGER.md)
|
|
493
|
-
return Path(".")
|
|
494
|
-
return self.exec_path_compensation / Path(*namespace.split("."))
|
|
495
|
-
|
|
496
504
|
# pylint: disable=line-too-long
|
|
497
505
|
@property
|
|
498
506
|
def sample_additional_folder(self) -> Path:
|
|
@@ -511,8 +519,8 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
511
519
|
return Path("/".join(namespace_config.split(".")[num_of_package_namespace:]))
|
|
512
520
|
return Path("")
|
|
513
521
|
|
|
514
|
-
def _serialize_and_write_sample(self, env: Environment
|
|
515
|
-
out_path =
|
|
522
|
+
def _serialize_and_write_sample(self, env: Environment):
|
|
523
|
+
out_path = Path("./generated_samples")
|
|
516
524
|
for client in self.code_model.clients:
|
|
517
525
|
for op_group in client.operation_groups:
|
|
518
526
|
for operation in op_group.operations:
|
|
@@ -544,9 +552,9 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
544
552
|
log_error = f"error happens in sample {file}: {e}"
|
|
545
553
|
_LOGGER.error(log_error)
|
|
546
554
|
|
|
547
|
-
def _serialize_and_write_test(self, env: Environment
|
|
555
|
+
def _serialize_and_write_test(self, env: Environment):
|
|
548
556
|
self.code_model.for_test = True
|
|
549
|
-
out_path =
|
|
557
|
+
out_path = Path("./generated_tests")
|
|
550
558
|
general_serializer = TestGeneralSerializer(code_model=self.code_model, env=env)
|
|
551
559
|
self.write_file(out_path / "conftest.py", general_serializer.serialize_conftest())
|
|
552
560
|
if not self.code_model.options["azure-arm"]:
|
|
@@ -1079,18 +1079,19 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]):
|
|
|
1079
1079
|
)
|
|
1080
1080
|
condition = "elif"
|
|
1081
1081
|
# default error handling
|
|
1082
|
-
|
|
1082
|
+
default_error_deserialization = builder.default_error_deserialization(self.serialize_namespace)
|
|
1083
|
+
if default_error_deserialization and self.code_model.options["models-mode"]:
|
|
1083
1084
|
error_model = ", model=error"
|
|
1084
1085
|
indent = " " if builder.non_default_errors else " "
|
|
1085
1086
|
if builder.non_default_errors:
|
|
1086
1087
|
retval.append(" else:")
|
|
1087
1088
|
if self.code_model.options["models-mode"] == "dpg":
|
|
1088
1089
|
retval.append(
|
|
1089
|
-
f"{indent}error = _failsafe_deserialize({
|
|
1090
|
+
f"{indent}error = _failsafe_deserialize({default_error_deserialization}, response.json())"
|
|
1090
1091
|
)
|
|
1091
1092
|
else:
|
|
1092
1093
|
retval.append(
|
|
1093
|
-
f"{indent}error = self._deserialize.failsafe_deserialize({
|
|
1094
|
+
f"{indent}error = self._deserialize.failsafe_deserialize({default_error_deserialization}, "
|
|
1094
1095
|
"pipeline_response)"
|
|
1095
1096
|
)
|
|
1096
1097
|
retval.append(
|