@autorest/python 6.37.2 → 6.38.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/autorest/__init__.py +13 -0
- package/autorest/codegen.py +1 -0
- package/generator/build/lib/pygen/__init__.py +32 -2
- package/generator/build/lib/pygen/codegen/models/code_model.py +32 -0
- package/generator/build/lib/pygen/codegen/models/enum_type.py +4 -1
- package/generator/build/lib/pygen/codegen/models/model_type.py +4 -1
- 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 +85 -74
- package/generator/build/lib/pygen/codegen/serializers/builder_serializer.py +7 -6
- package/generator/build/lib/pygen/codegen/serializers/general_serializer.py +86 -13
- package/generator/build/lib/pygen/codegen/templates/model_base.py.jinja2 +5 -4
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/pyproject.toml.jinja2 +109 -0
- package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
- package/generator/pygen/__init__.py +32 -2
- package/generator/pygen/codegen/models/code_model.py +32 -0
- package/generator/pygen/codegen/models/enum_type.py +4 -1
- package/generator/pygen/codegen/models/model_type.py +4 -1
- 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 +85 -74
- package/generator/pygen/codegen/serializers/builder_serializer.py +7 -6
- package/generator/pygen/codegen/serializers/general_serializer.py +86 -13
- package/generator/pygen/codegen/templates/model_base.py.jinja2 +5 -4
- package/generator/pygen/codegen/templates/packaging_templates/pyproject.toml.jinja2 +109 -0
- package/generator/pygen.egg-info/SOURCES.txt +1 -0
- package/package.json +2 -2
- package/scripts/__pycache__/venvtools.cpython-310.pyc +0 -0
|
@@ -7,8 +7,9 @@ import logging
|
|
|
7
7
|
import json
|
|
8
8
|
from collections import namedtuple
|
|
9
9
|
import re
|
|
10
|
-
from typing import List, Any, Union
|
|
10
|
+
from typing import List, Any, Union, Optional
|
|
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
|
+
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"),
|
|
@@ -231,9 +252,10 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
231
252
|
if self.keep_version_file and file == "setup.py" and not self.code_model.options["azure-arm"]:
|
|
232
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,29 @@ 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,
|
|
379
|
+
namespace: Optional[str] = None,
|
|
358
380
|
):
|
|
359
|
-
|
|
381
|
+
if namespace:
|
|
382
|
+
generation_path = self.code_model.get_generation_dir(namespace)
|
|
383
|
+
else:
|
|
384
|
+
generation_path = self.code_model.get_root_dir()
|
|
360
385
|
|
|
361
386
|
def _read_version_file(original_version_file_name: str) -> str:
|
|
362
|
-
return self.read_file(
|
|
387
|
+
return self.read_file(generation_path / original_version_file_name)
|
|
363
388
|
|
|
364
389
|
def _write_version_file(original_version_file_name: str) -> None:
|
|
365
390
|
self.write_file(
|
|
366
|
-
|
|
391
|
+
generation_path / Path("_version.py"),
|
|
367
392
|
_read_version_file(original_version_file_name),
|
|
368
393
|
)
|
|
369
394
|
|
|
@@ -373,7 +398,7 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
373
398
|
_write_version_file(original_version_file_name="version.py")
|
|
374
399
|
elif self.code_model.options.get("package-version"):
|
|
375
400
|
self.write_file(
|
|
376
|
-
|
|
401
|
+
generation_path / Path("_version.py"),
|
|
377
402
|
general_serializer.serialize_version_file(),
|
|
378
403
|
)
|
|
379
404
|
|
|
@@ -383,47 +408,47 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
383
408
|
clients: List[Client],
|
|
384
409
|
env: Environment,
|
|
385
410
|
) -> None:
|
|
386
|
-
|
|
411
|
+
generation_path = self.code_model.get_generation_dir(namespace)
|
|
387
412
|
for async_mode, async_path in self.serialize_loop:
|
|
388
413
|
general_serializer = GeneralSerializer(
|
|
389
414
|
code_model=self.code_model, env=env, async_mode=async_mode, client_namespace=namespace
|
|
390
415
|
)
|
|
391
416
|
# when there is client.py, there must be __init__.py
|
|
392
417
|
self.write_file(
|
|
393
|
-
|
|
418
|
+
generation_path / Path(f"{async_path}__init__.py"),
|
|
394
419
|
general_serializer.serialize_init_file([c for c in clients if c.has_operations]),
|
|
395
420
|
)
|
|
396
421
|
|
|
397
422
|
# if there was a patch file before, we keep it
|
|
398
|
-
self._keep_patch_file(
|
|
423
|
+
self._keep_patch_file(generation_path / Path(f"{async_path}_patch.py"), env)
|
|
399
424
|
|
|
400
425
|
if self.code_model.clients_has_operations(clients):
|
|
401
426
|
|
|
402
427
|
# write client file
|
|
403
428
|
self.write_file(
|
|
404
|
-
|
|
429
|
+
generation_path / Path(f"{async_path}{self.code_model.client_filename}.py"),
|
|
405
430
|
general_serializer.serialize_service_client_file(clients),
|
|
406
431
|
)
|
|
407
432
|
|
|
408
433
|
# write config file
|
|
409
434
|
self.write_file(
|
|
410
|
-
|
|
435
|
+
generation_path / Path(f"{async_path}_configuration.py"),
|
|
411
436
|
general_serializer.serialize_config_file(clients),
|
|
412
437
|
)
|
|
413
438
|
|
|
414
439
|
# sometimes we need define additional Mixin class for client in _utils.py
|
|
415
440
|
self._serialize_and_write_utils_folder(env, namespace)
|
|
416
441
|
|
|
417
|
-
def _serialize_and_write_utils_folder(self, env: Environment, namespace: str)
|
|
418
|
-
|
|
442
|
+
def _serialize_and_write_utils_folder(self, env: Environment, namespace: str):
|
|
443
|
+
generation_dir = self.code_model.get_generation_dir(namespace)
|
|
419
444
|
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):
|
|
445
|
+
utils_folder_path = generation_dir / Path("_utils")
|
|
446
|
+
if self.code_model.need_utils_folder(async_mode=False, client_namespace=self.code_model.namespace):
|
|
422
447
|
self.write_file(
|
|
423
448
|
utils_folder_path / Path("__init__.py"),
|
|
424
449
|
self.code_model.license_header,
|
|
425
450
|
)
|
|
426
|
-
if self.code_model.need_utils_utils(async_mode=False, client_namespace=namespace):
|
|
451
|
+
if self.code_model.need_utils_utils(async_mode=False, client_namespace=self.code_model.namespace):
|
|
427
452
|
self.write_file(
|
|
428
453
|
utils_folder_path / Path("utils.py"),
|
|
429
454
|
general_serializer.need_utils_utils_file(),
|
|
@@ -443,60 +468,46 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
443
468
|
)
|
|
444
469
|
|
|
445
470
|
def _serialize_and_write_top_level_folder(self, env: Environment, namespace: str) -> None:
|
|
446
|
-
|
|
471
|
+
root_dir = self.code_model.get_root_dir()
|
|
447
472
|
# write _utils folder
|
|
448
|
-
self._serialize_and_write_utils_folder(env, namespace)
|
|
473
|
+
self._serialize_and_write_utils_folder(env, self.code_model.namespace)
|
|
449
474
|
|
|
450
475
|
general_serializer = GeneralSerializer(code_model=self.code_model, env=env, async_mode=False)
|
|
451
476
|
|
|
452
477
|
# write _version.py
|
|
453
|
-
self._serialize_and_write_version_file(
|
|
478
|
+
self._serialize_and_write_version_file(general_serializer)
|
|
479
|
+
# if there's a subdir, we need to write another version file in the subdir
|
|
480
|
+
if self.code_model.options.get("generation-subdir"):
|
|
481
|
+
self._serialize_and_write_version_file(general_serializer, namespace)
|
|
454
482
|
|
|
455
483
|
# write the empty py.typed file
|
|
456
|
-
|
|
484
|
+
pytyped_value = "# Marker file for PEP 561."
|
|
485
|
+
# TODO: remove this when we remove legacy multiapi generation
|
|
486
|
+
if self.code_model.options["multiapi"]:
|
|
487
|
+
self.write_file(self.code_model.get_generation_dir(namespace) / Path("py.typed"), pytyped_value)
|
|
488
|
+
else:
|
|
489
|
+
self.write_file(root_dir / Path("py.typed"), pytyped_value)
|
|
457
490
|
|
|
458
491
|
# write _validation.py
|
|
459
492
|
if any(og for client in self.code_model.clients for og in client.operation_groups if og.need_validation):
|
|
460
493
|
self.write_file(
|
|
461
|
-
|
|
494
|
+
root_dir / Path("_validation.py"),
|
|
462
495
|
general_serializer.serialize_validation_file(),
|
|
463
496
|
)
|
|
464
497
|
|
|
465
498
|
# write _types.py
|
|
466
499
|
if self.code_model.named_unions:
|
|
467
500
|
self.write_file(
|
|
468
|
-
|
|
501
|
+
root_dir / Path("_types.py"),
|
|
469
502
|
TypesSerializer(code_model=self.code_model, env=env).serialize(),
|
|
470
503
|
)
|
|
471
504
|
|
|
472
505
|
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(".")
|
|
506
|
+
metadata_serializer = MetadataSerializer(self.code_model, env)
|
|
507
|
+
self.write_file(
|
|
508
|
+
self.code_model.get_generation_dir(namespace) / Path("_metadata.json"), metadata_serializer.serialize()
|
|
483
509
|
)
|
|
484
510
|
|
|
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 (
|
|
491
|
-
self.code_model.options["no-namespace-folders"]
|
|
492
|
-
and not self.code_model.options["multiapi"]
|
|
493
|
-
and not self.code_model.options["azure-arm"]
|
|
494
|
-
):
|
|
495
|
-
# when output folder contains parts different from the namespace, we fall back to current folder directly.
|
|
496
|
-
# (e.g. https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/communication/azure-communication-callautomation/swagger/SWAGGER.md)
|
|
497
|
-
return Path(".")
|
|
498
|
-
return self.exec_path_compensation / Path(*namespace.split("."))
|
|
499
|
-
|
|
500
511
|
# pylint: disable=line-too-long
|
|
501
512
|
@property
|
|
502
513
|
def sample_additional_folder(self) -> Path:
|
|
@@ -515,8 +526,8 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
515
526
|
return Path("/".join(namespace_config.split(".")[num_of_package_namespace:]))
|
|
516
527
|
return Path("")
|
|
517
528
|
|
|
518
|
-
def _serialize_and_write_sample(self, env: Environment
|
|
519
|
-
out_path =
|
|
529
|
+
def _serialize_and_write_sample(self, env: Environment):
|
|
530
|
+
out_path = Path("./generated_samples")
|
|
520
531
|
for client in self.code_model.clients:
|
|
521
532
|
for op_group in client.operation_groups:
|
|
522
533
|
for operation in op_group.operations:
|
|
@@ -548,9 +559,9 @@ class JinjaSerializer(ReaderAndWriter):
|
|
|
548
559
|
log_error = f"error happens in sample {file}: {e}"
|
|
549
560
|
_LOGGER.error(log_error)
|
|
550
561
|
|
|
551
|
-
def _serialize_and_write_test(self, env: Environment
|
|
562
|
+
def _serialize_and_write_test(self, env: Environment):
|
|
552
563
|
self.code_model.for_test = True
|
|
553
|
-
out_path =
|
|
564
|
+
out_path = Path("./generated_tests")
|
|
554
565
|
general_serializer = TestGeneralSerializer(code_model=self.code_model, env=env)
|
|
555
566
|
self.write_file(out_path / "conftest.py", general_serializer.serialize_conftest())
|
|
556
567
|
if not self.code_model.options["azure-arm"]:
|
|
@@ -1032,7 +1032,7 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]):
|
|
|
1032
1032
|
is_operation_file=True, skip_quote=True, serialize_namespace=self.serialize_namespace
|
|
1033
1033
|
)
|
|
1034
1034
|
if self.code_model.options["models-mode"] == "dpg":
|
|
1035
|
-
retval.append(f" error = _failsafe_deserialize({type_annotation}, response
|
|
1035
|
+
retval.append(f" error = _failsafe_deserialize({type_annotation}, response)")
|
|
1036
1036
|
else:
|
|
1037
1037
|
retval.append(
|
|
1038
1038
|
f" error = self._deserialize.failsafe_deserialize({type_annotation}, "
|
|
@@ -1068,10 +1068,10 @@ class _OperationSerializer(_BuilderBaseSerializer[OperationType]):
|
|
|
1068
1068
|
if self.code_model.options["models-mode"] == "dpg":
|
|
1069
1069
|
if xml_serializable(str(e.default_content_type)):
|
|
1070
1070
|
retval.append(
|
|
1071
|
-
f" error = _failsafe_deserialize_xml({type_annotation},
|
|
1071
|
+
f" error = _failsafe_deserialize_xml({type_annotation}, response)"
|
|
1072
1072
|
)
|
|
1073
1073
|
else:
|
|
1074
|
-
retval.append(f" error = _failsafe_deserialize({type_annotation},
|
|
1074
|
+
retval.append(f" error = _failsafe_deserialize({type_annotation}, response)")
|
|
1075
1075
|
else:
|
|
1076
1076
|
retval.append(
|
|
1077
1077
|
f" error = self._deserialize.failsafe_deserialize({type_annotation}, "
|
|
@@ -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)"
|
|
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(
|
|
@@ -4,7 +4,10 @@
|
|
|
4
4
|
# license information.
|
|
5
5
|
# --------------------------------------------------------------------------
|
|
6
6
|
import json
|
|
7
|
-
from typing import Any, List
|
|
7
|
+
from typing import Any, List, TYPE_CHECKING
|
|
8
|
+
import re
|
|
9
|
+
import tomli as tomllib
|
|
10
|
+
from packaging.version import parse as parse_version
|
|
8
11
|
from .import_serializer import FileImportSerializer, TypingSection
|
|
9
12
|
from ..models.imports import MsrestImportType, FileImport
|
|
10
13
|
from ..models import (
|
|
@@ -16,6 +19,9 @@ from ..models.utils import NamespaceType
|
|
|
16
19
|
from .client_serializer import ClientSerializer, ConfigSerializer
|
|
17
20
|
from .base_serializer import BaseSerializer
|
|
18
21
|
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from pathlib import Path
|
|
24
|
+
|
|
19
25
|
VERSION_MAP = {
|
|
20
26
|
"msrest": "0.7.1",
|
|
21
27
|
"isodate": "0.6.1",
|
|
@@ -42,8 +48,73 @@ class GeneralSerializer(BaseSerializer):
|
|
|
42
48
|
params.update({"options": self.code_model.options})
|
|
43
49
|
return template.render(code_model=self.code_model, **params)
|
|
44
50
|
|
|
45
|
-
def
|
|
51
|
+
def _extract_min_dependency(self, s):
|
|
52
|
+
# Extract the minimum version from a dependency string.
|
|
53
|
+
#
|
|
54
|
+
# Handles formats like:
|
|
55
|
+
# - >=1.2.3
|
|
56
|
+
# - >=0.1.0b1 (beta versions)
|
|
57
|
+
# - >=1.2.3rc2 (release candidates)
|
|
58
|
+
#
|
|
59
|
+
# Returns the parsed version if found, otherwise version "0".
|
|
60
|
+
m = re.search(r"[>=]=?([\d.]+(?:[a-z]+\d+)?)", s)
|
|
61
|
+
return parse_version(m.group(1)) if m else parse_version("0")
|
|
62
|
+
|
|
63
|
+
def _keep_pyproject_fields(self, file_path: "Path") -> dict:
|
|
64
|
+
# Load the pyproject.toml file if it exists and extract fields to keep.
|
|
65
|
+
result: dict = {"KEEP_FIELDS": {}}
|
|
66
|
+
try:
|
|
67
|
+
with open(file_path, "rb") as f:
|
|
68
|
+
loaded_pyproject_toml = tomllib.load(f)
|
|
69
|
+
except Exception: # pylint: disable=broad-except
|
|
70
|
+
# If parsing the pyproject.toml fails, we assume the it does not exist or is incorrectly formatted.
|
|
71
|
+
return result
|
|
72
|
+
|
|
73
|
+
# Keep azure-sdk-build configuration
|
|
74
|
+
if "tool" in loaded_pyproject_toml and "azure-sdk-build" in loaded_pyproject_toml["tool"]:
|
|
75
|
+
result["KEEP_FIELDS"]["tool.azure-sdk-build"] = loaded_pyproject_toml["tool"]["azure-sdk-build"]
|
|
76
|
+
|
|
77
|
+
# Process dependencies
|
|
78
|
+
if "project" in loaded_pyproject_toml:
|
|
79
|
+
# Handle main dependencies
|
|
80
|
+
if "dependencies" in loaded_pyproject_toml["project"]:
|
|
81
|
+
kept_deps = []
|
|
82
|
+
for dep in loaded_pyproject_toml["project"]["dependencies"]:
|
|
83
|
+
dep_name = re.split(r"[<>=\[]", dep)[0].strip()
|
|
84
|
+
|
|
85
|
+
# Check if dependency is one we track in VERSION_MAP
|
|
86
|
+
if dep_name in VERSION_MAP:
|
|
87
|
+
# For tracked dependencies, check if the version is higher than our default
|
|
88
|
+
default_version = parse_version(VERSION_MAP[dep_name])
|
|
89
|
+
dep_version = self._extract_min_dependency(dep)
|
|
90
|
+
# If the version is higher than the default, update VERSION_MAP
|
|
91
|
+
# with higher min dependency version
|
|
92
|
+
if dep_version > default_version:
|
|
93
|
+
VERSION_MAP[dep_name] = str(dep_version)
|
|
94
|
+
else:
|
|
95
|
+
# Keep non-default dependencies
|
|
96
|
+
kept_deps.append(dep)
|
|
97
|
+
|
|
98
|
+
if kept_deps:
|
|
99
|
+
result["KEEP_FIELDS"]["project.dependencies"] = kept_deps
|
|
100
|
+
|
|
101
|
+
# Keep optional dependencies
|
|
102
|
+
if "optional-dependencies" in loaded_pyproject_toml["project"]:
|
|
103
|
+
result["KEEP_FIELDS"]["project.optional-dependencies"] = loaded_pyproject_toml["project"][
|
|
104
|
+
"optional-dependencies"
|
|
105
|
+
]
|
|
106
|
+
|
|
107
|
+
return result
|
|
108
|
+
|
|
109
|
+
def serialize_package_file(self, template_name: str, file_path: "Path", **kwargs: Any) -> str:
|
|
46
110
|
template = self.env.get_template(template_name)
|
|
111
|
+
|
|
112
|
+
# Add fields to keep from an existing pyproject.toml
|
|
113
|
+
if template_name == "pyproject.toml.jinja2":
|
|
114
|
+
params = self._keep_pyproject_fields(file_path)
|
|
115
|
+
else:
|
|
116
|
+
params = {}
|
|
117
|
+
|
|
47
118
|
package_parts = (
|
|
48
119
|
self.code_model.namespace.split(".")[:-1]
|
|
49
120
|
if self.code_model.is_tsp
|
|
@@ -57,17 +128,19 @@ class GeneralSerializer(BaseSerializer):
|
|
|
57
128
|
dev_status = "4 - Beta"
|
|
58
129
|
else:
|
|
59
130
|
dev_status = "5 - Production/Stable"
|
|
60
|
-
params
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
131
|
+
params.update(
|
|
132
|
+
{
|
|
133
|
+
"code_model": self.code_model,
|
|
134
|
+
"dev_status": dev_status,
|
|
135
|
+
"token_credential": token_credential,
|
|
136
|
+
"pkgutil_names": [".".join(package_parts[: i + 1]) for i in range(len(package_parts))],
|
|
137
|
+
"init_names": ["/".join(package_parts[: i + 1]) + "/__init__.py" for i in range(len(package_parts))],
|
|
138
|
+
"client_name": self.code_model.clients[0].name if self.code_model.clients else "",
|
|
139
|
+
"VERSION_MAP": VERSION_MAP,
|
|
140
|
+
"MIN_PYTHON_VERSION": MIN_PYTHON_VERSION,
|
|
141
|
+
"MAX_PYTHON_VERSION": MAX_PYTHON_VERSION,
|
|
142
|
+
}
|
|
143
|
+
)
|
|
71
144
|
params.update({"options": self.code_model.options})
|
|
72
145
|
params.update(kwargs)
|
|
73
146
|
return template.render(file_import=FileImport(self.code_model), **params)
|
|
@@ -25,6 +25,7 @@ from {{ code_model.core_library }}.exceptions import DeserializationError
|
|
|
25
25
|
from {{ code_model.core_library }}{{ "" if code_model.is_azure_flavor else ".utils" }} import CaseInsensitiveEnumMeta
|
|
26
26
|
from {{ code_model.core_library }}.{{ "" if code_model.is_azure_flavor else "runtime." }}pipeline import PipelineResponse
|
|
27
27
|
from {{ code_model.core_library }}.serialization import _Null
|
|
28
|
+
from {{ code_model.core_library }}.rest import HttpResponse
|
|
28
29
|
|
|
29
30
|
_LOGGER = logging.getLogger(__name__)
|
|
30
31
|
|
|
@@ -935,13 +936,13 @@ def _deserialize(
|
|
|
935
936
|
|
|
936
937
|
def _failsafe_deserialize(
|
|
937
938
|
deserializer: typing.Any,
|
|
938
|
-
|
|
939
|
+
response: HttpResponse,
|
|
939
940
|
module: typing.Optional[str] = None,
|
|
940
941
|
rf: typing.Optional["_RestField"] = None,
|
|
941
942
|
format: typing.Optional[str] = None,
|
|
942
943
|
) -> typing.Any:
|
|
943
944
|
try:
|
|
944
|
-
return _deserialize(deserializer,
|
|
945
|
+
return _deserialize(deserializer, response.json(), module, rf, format)
|
|
945
946
|
except DeserializationError:
|
|
946
947
|
_LOGGER.warning(
|
|
947
948
|
"Ran into a deserialization error. Ignoring since this is failsafe deserialization",
|
|
@@ -952,10 +953,10 @@ def _failsafe_deserialize(
|
|
|
952
953
|
|
|
953
954
|
def _failsafe_deserialize_xml(
|
|
954
955
|
deserializer: typing.Any,
|
|
955
|
-
|
|
956
|
+
response: HttpResponse,
|
|
956
957
|
) -> typing.Any:
|
|
957
958
|
try:
|
|
958
|
-
return _deserialize_xml(deserializer,
|
|
959
|
+
return _deserialize_xml(deserializer, response.text())
|
|
959
960
|
except DeserializationError:
|
|
960
961
|
_LOGGER.warning(
|
|
961
962
|
"Ran into a deserialization error. Ignoring since this is failsafe deserialization",
|