@typespec/http-client-python 0.4.3 → 0.5.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/dist/emitter/emitter.d.ts.map +1 -1
- package/dist/emitter/emitter.js +85 -24
- 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 +1 -0
- package/dist/emitter/lib.js.map +1 -1
- package/dist/emitter/run-python3.d.ts +2 -0
- package/dist/emitter/run-python3.d.ts.map +1 -0
- package/dist/emitter/run-python3.js +19 -0
- package/dist/emitter/run-python3.js.map +1 -0
- package/dist/emitter/system-requirements.d.ts +17 -0
- package/dist/emitter/system-requirements.d.ts.map +1 -0
- package/dist/emitter/system-requirements.js +167 -0
- package/dist/emitter/system-requirements.js.map +1 -0
- package/emitter/src/emitter.ts +88 -23
- package/emitter/src/lib.ts +2 -0
- package/emitter/src/run-python3.ts +20 -0
- package/emitter/src/system-requirements.ts +261 -0
- package/emitter/temp/tsconfig.tsbuildinfo +1 -1
- package/eng/scripts/ci/regenerate.ts +16 -4
- package/eng/scripts/setup/__pycache__/venvtools.cpython-38.pyc +0 -0
- package/eng/scripts/setup/build.ts +16 -0
- package/eng/scripts/setup/build_pygen_wheel.py +40 -0
- package/eng/scripts/setup/install.py +9 -3
- package/eng/scripts/setup/install.ts +32 -0
- package/eng/scripts/setup/prepare.py +3 -1
- package/eng/scripts/setup/prepare.ts +11 -0
- package/eng/scripts/setup/run-python3.ts +1 -6
- package/generator/build/lib/pygen/__init__.py +107 -0
- package/generator/build/lib/pygen/_version.py +7 -0
- package/generator/build/lib/pygen/black.py +71 -0
- package/generator/build/lib/pygen/codegen/__init__.py +357 -0
- package/generator/build/lib/pygen/codegen/_utils.py +17 -0
- package/generator/build/lib/pygen/codegen/models/__init__.py +204 -0
- package/generator/build/lib/pygen/codegen/models/base.py +186 -0
- package/generator/build/lib/pygen/codegen/models/base_builder.py +118 -0
- package/generator/build/lib/pygen/codegen/models/client.py +435 -0
- package/generator/build/lib/pygen/codegen/models/code_model.py +237 -0
- package/generator/build/lib/pygen/codegen/models/combined_type.py +149 -0
- package/generator/build/lib/pygen/codegen/models/constant_type.py +129 -0
- package/generator/build/lib/pygen/codegen/models/credential_types.py +214 -0
- package/generator/build/lib/pygen/codegen/models/dictionary_type.py +127 -0
- package/generator/build/lib/pygen/codegen/models/enum_type.py +238 -0
- package/generator/build/lib/pygen/codegen/models/imports.py +291 -0
- package/generator/build/lib/pygen/codegen/models/list_type.py +143 -0
- package/generator/build/lib/pygen/codegen/models/lro_operation.py +142 -0
- package/generator/build/lib/pygen/codegen/models/lro_paging_operation.py +32 -0
- package/generator/build/lib/pygen/codegen/models/model_type.py +357 -0
- package/generator/build/lib/pygen/codegen/models/operation.py +509 -0
- package/generator/build/lib/pygen/codegen/models/operation_group.py +184 -0
- package/generator/build/lib/pygen/codegen/models/paging_operation.py +155 -0
- package/generator/build/lib/pygen/codegen/models/parameter.py +412 -0
- package/generator/build/lib/pygen/codegen/models/parameter_list.py +387 -0
- package/generator/build/lib/pygen/codegen/models/primitive_types.py +659 -0
- package/generator/build/lib/pygen/codegen/models/property.py +170 -0
- package/generator/build/lib/pygen/codegen/models/request_builder.py +189 -0
- package/generator/build/lib/pygen/codegen/models/request_builder_parameter.py +115 -0
- package/generator/build/lib/pygen/codegen/models/response.py +348 -0
- package/generator/build/lib/pygen/codegen/models/utils.py +21 -0
- package/generator/build/lib/pygen/codegen/serializers/__init__.py +574 -0
- package/generator/build/lib/pygen/codegen/serializers/base_serializer.py +21 -0
- package/generator/build/lib/pygen/codegen/serializers/builder_serializer.py +1533 -0
- package/generator/build/lib/pygen/codegen/serializers/client_serializer.py +294 -0
- package/generator/build/lib/pygen/codegen/serializers/enum_serializer.py +15 -0
- package/generator/build/lib/pygen/codegen/serializers/general_serializer.py +213 -0
- package/generator/build/lib/pygen/codegen/serializers/import_serializer.py +126 -0
- package/generator/build/lib/pygen/codegen/serializers/metadata_serializer.py +198 -0
- package/generator/build/lib/pygen/codegen/serializers/model_init_serializer.py +33 -0
- package/generator/build/lib/pygen/codegen/serializers/model_serializer.py +335 -0
- package/generator/build/lib/pygen/codegen/serializers/operation_groups_serializer.py +89 -0
- package/generator/build/lib/pygen/codegen/serializers/operations_init_serializer.py +44 -0
- package/generator/build/lib/pygen/codegen/serializers/parameter_serializer.py +221 -0
- package/generator/build/lib/pygen/codegen/serializers/patch_serializer.py +19 -0
- package/generator/build/lib/pygen/codegen/serializers/request_builders_serializer.py +52 -0
- package/generator/build/lib/pygen/codegen/serializers/sample_serializer.py +168 -0
- package/generator/build/lib/pygen/codegen/serializers/test_serializer.py +292 -0
- package/generator/build/lib/pygen/codegen/serializers/types_serializer.py +31 -0
- package/generator/build/lib/pygen/codegen/serializers/utils.py +68 -0
- package/generator/build/lib/pygen/codegen/templates/client.py.jinja2 +37 -0
- package/generator/build/lib/pygen/codegen/templates/client_container.py.jinja2 +12 -0
- package/generator/build/lib/pygen/codegen/templates/config.py.jinja2 +73 -0
- package/generator/build/lib/pygen/codegen/templates/config_container.py.jinja2 +16 -0
- package/generator/build/lib/pygen/codegen/templates/conftest.py.jinja2 +28 -0
- package/generator/build/lib/pygen/codegen/templates/enum.py.jinja2 +13 -0
- package/generator/build/lib/pygen/codegen/templates/enum_container.py.jinja2 +10 -0
- package/generator/build/lib/pygen/codegen/templates/init.py.jinja2 +24 -0
- package/generator/build/lib/pygen/codegen/templates/keywords.jinja2 +27 -0
- package/generator/build/lib/pygen/codegen/templates/lro_operation.py.jinja2 +16 -0
- package/generator/build/lib/pygen/codegen/templates/lro_paging_operation.py.jinja2 +18 -0
- package/generator/build/lib/pygen/codegen/templates/macros.jinja2 +12 -0
- package/generator/build/lib/pygen/codegen/templates/metadata.json.jinja2 +167 -0
- package/generator/build/lib/pygen/codegen/templates/model_base.py.jinja2 +1174 -0
- package/generator/build/lib/pygen/codegen/templates/model_container.py.jinja2 +15 -0
- package/generator/build/lib/pygen/codegen/templates/model_dpg.py.jinja2 +97 -0
- package/generator/build/lib/pygen/codegen/templates/model_init.py.jinja2 +33 -0
- package/generator/build/lib/pygen/codegen/templates/model_msrest.py.jinja2 +92 -0
- package/generator/build/lib/pygen/codegen/templates/operation.py.jinja2 +21 -0
- package/generator/build/lib/pygen/codegen/templates/operation_group.py.jinja2 +75 -0
- package/generator/build/lib/pygen/codegen/templates/operation_groups_container.py.jinja2 +19 -0
- package/generator/build/lib/pygen/codegen/templates/operation_tools.jinja2 +81 -0
- package/generator/build/lib/pygen/codegen/templates/operations_folder_init.py.jinja2 +17 -0
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/CHANGELOG.md.jinja2 +6 -0
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/LICENSE.jinja2 +21 -0
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/MANIFEST.in.jinja2 +8 -0
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/README.md.jinja2 +107 -0
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/dev_requirements.txt.jinja2 +9 -0
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/setup.py.jinja2 +108 -0
- package/generator/build/lib/pygen/codegen/templates/paging_operation.py.jinja2 +21 -0
- package/generator/build/lib/pygen/codegen/templates/patch.py.jinja2 +19 -0
- package/generator/build/lib/pygen/codegen/templates/pkgutil_init.py.jinja2 +1 -0
- package/generator/build/lib/pygen/codegen/templates/request_builder.py.jinja2 +28 -0
- package/generator/build/lib/pygen/codegen/templates/request_builders.py.jinja2 +10 -0
- package/generator/build/lib/pygen/codegen/templates/rest_init.py.jinja2 +12 -0
- package/generator/build/lib/pygen/codegen/templates/sample.py.jinja2 +44 -0
- package/generator/build/lib/pygen/codegen/templates/serialization.py.jinja2 +2117 -0
- package/generator/build/lib/pygen/codegen/templates/test.py.jinja2 +50 -0
- package/generator/build/lib/pygen/codegen/templates/testpreparer.py.jinja2 +26 -0
- package/generator/build/lib/pygen/codegen/templates/types.py.jinja2 +7 -0
- package/generator/build/lib/pygen/codegen/templates/validation.py.jinja2 +38 -0
- package/generator/build/lib/pygen/codegen/templates/vendor.py.jinja2 +96 -0
- package/generator/build/lib/pygen/codegen/templates/version.py.jinja2 +4 -0
- package/generator/build/lib/pygen/m2r.py +65 -0
- package/generator/build/lib/pygen/preprocess/__init__.py +515 -0
- package/generator/build/lib/pygen/preprocess/helpers.py +27 -0
- package/generator/build/lib/pygen/preprocess/python_mappings.py +226 -0
- package/generator/build/lib/pygen/utils.py +163 -0
- package/generator/component-detection-pip-report.json +134 -0
- package/generator/dev_requirements.txt +0 -1
- package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
- package/generator/pygen/m2r.py +1 -1
- package/generator/pygen.egg-info/PKG-INFO +7 -4
- package/generator/pygen.egg-info/requires.txt +7 -4
- package/generator/requirements.txt +5 -10
- package/generator/setup.py +7 -4
- package/generator/test/azure/requirements.txt +2 -0
- package/generator/test/generic_mock_api_tests/unittests/test_m2r.py +10 -0
- package/generator/test/unbranded/requirements.txt +2 -0
- package/package.json +6 -5
|
@@ -0,0 +1,574 @@
|
|
|
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 List, Optional, Any, Union
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from jinja2 import PackageLoader, Environment, FileSystemLoader, StrictUndefined
|
|
10
|
+
|
|
11
|
+
from ... import ReaderAndWriter
|
|
12
|
+
from ..models import (
|
|
13
|
+
OperationGroup,
|
|
14
|
+
RequestBuilder,
|
|
15
|
+
OverloadedRequestBuilder,
|
|
16
|
+
CodeModel,
|
|
17
|
+
Client,
|
|
18
|
+
)
|
|
19
|
+
from .enum_serializer import EnumSerializer
|
|
20
|
+
from .general_serializer import GeneralSerializer
|
|
21
|
+
from .model_init_serializer import ModelInitSerializer
|
|
22
|
+
from .model_serializer import DpgModelSerializer, MsrestModelSerializer
|
|
23
|
+
from .operations_init_serializer import OperationsInitSerializer
|
|
24
|
+
from .operation_groups_serializer import OperationGroupsSerializer
|
|
25
|
+
from .metadata_serializer import MetadataSerializer
|
|
26
|
+
from .request_builders_serializer import RequestBuildersSerializer
|
|
27
|
+
from .patch_serializer import PatchSerializer
|
|
28
|
+
from .sample_serializer import SampleSerializer
|
|
29
|
+
from .test_serializer import TestSerializer, TestGeneralSerializer
|
|
30
|
+
from .types_serializer import TypesSerializer
|
|
31
|
+
from ...utils import to_snake_case
|
|
32
|
+
from .._utils import VALID_PACKAGE_MODE
|
|
33
|
+
from .utils import (
|
|
34
|
+
extract_sample_name,
|
|
35
|
+
get_namespace_from_package_name,
|
|
36
|
+
get_namespace_config,
|
|
37
|
+
get_all_operation_groups_recursively,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
_LOGGER = logging.getLogger(__name__)
|
|
41
|
+
|
|
42
|
+
__all__ = [
|
|
43
|
+
"JinjaSerializer",
|
|
44
|
+
]
|
|
45
|
+
|
|
46
|
+
_PACKAGE_FILES = [
|
|
47
|
+
"CHANGELOG.md.jinja2",
|
|
48
|
+
"dev_requirements.txt.jinja2",
|
|
49
|
+
"LICENSE.jinja2",
|
|
50
|
+
"MANIFEST.in.jinja2",
|
|
51
|
+
"README.md.jinja2",
|
|
52
|
+
"setup.py.jinja2",
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
_REGENERATE_FILES = {"setup.py", "MANIFEST.in"}
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
# extract sub folders. For example, source_file_path is like:
|
|
59
|
+
# "xxx/resource-manager/Microsoft.XX/stable/2023-04-01/examples/Compute/createOrUpdate/AKSCompute.json",
|
|
60
|
+
# and we want to extract the sub folders after "examples/", which is "compute/create_or_update"
|
|
61
|
+
def _sample_output_path(source_file_path: str) -> Path:
|
|
62
|
+
posix_path = Path(source_file_path).as_posix()
|
|
63
|
+
if "examples/" in posix_path:
|
|
64
|
+
after_examples = Path(posix_path.split("examples/", maxsplit=1)[-1]).parent
|
|
65
|
+
return Path("/".join([to_snake_case(i) for i in after_examples.parts]))
|
|
66
|
+
return Path("")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
class JinjaSerializer(ReaderAndWriter):
|
|
70
|
+
def __init__(
|
|
71
|
+
self,
|
|
72
|
+
code_model: CodeModel,
|
|
73
|
+
*,
|
|
74
|
+
output_folder: Union[str, Path],
|
|
75
|
+
**kwargs: Any,
|
|
76
|
+
) -> None:
|
|
77
|
+
super().__init__(output_folder=output_folder, **kwargs)
|
|
78
|
+
self.code_model = code_model
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def has_aio_folder(self) -> bool:
|
|
82
|
+
return not self.code_model.options["no_async"] and bool(self.code_model.has_operations)
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def has_operations_folder(self) -> bool:
|
|
86
|
+
return self.code_model.options["show_operations"] and bool(self.code_model.has_operations)
|
|
87
|
+
|
|
88
|
+
def _serialize_namespace_level(self, env: Environment, namespace_path: Path, clients: List[Client]) -> None:
|
|
89
|
+
# if there was a patch file before, we keep it
|
|
90
|
+
self._keep_patch_file(namespace_path / Path("_patch.py"), env)
|
|
91
|
+
if self.has_aio_folder:
|
|
92
|
+
self._keep_patch_file(namespace_path / Path("aio") / Path("_patch.py"), env)
|
|
93
|
+
|
|
94
|
+
if self.has_operations_folder:
|
|
95
|
+
self._keep_patch_file(
|
|
96
|
+
namespace_path / Path(self.code_model.operations_folder_name) / Path("_patch.py"),
|
|
97
|
+
env,
|
|
98
|
+
)
|
|
99
|
+
if self.has_aio_folder:
|
|
100
|
+
self._keep_patch_file(
|
|
101
|
+
namespace_path / Path("aio") / Path(self.code_model.operations_folder_name) / Path("_patch.py"),
|
|
102
|
+
env,
|
|
103
|
+
)
|
|
104
|
+
self._serialize_and_write_top_level_folder(env=env, namespace_path=namespace_path, clients=clients)
|
|
105
|
+
|
|
106
|
+
if any(c for c in self.code_model.clients if c.operation_groups):
|
|
107
|
+
if self.code_model.options["builders_visibility"] != "embedded":
|
|
108
|
+
self._serialize_and_write_rest_layer(env=env, namespace_path=namespace_path)
|
|
109
|
+
if self.has_aio_folder:
|
|
110
|
+
self._serialize_and_write_aio_top_level_folder(
|
|
111
|
+
env=env,
|
|
112
|
+
namespace_path=namespace_path,
|
|
113
|
+
clients=clients,
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
if self.has_operations_folder:
|
|
117
|
+
self._serialize_and_write_operations_folder(clients, env=env, namespace_path=namespace_path)
|
|
118
|
+
if self.code_model.options["multiapi"]:
|
|
119
|
+
self._serialize_and_write_metadata(env=env, namespace_path=namespace_path)
|
|
120
|
+
if self.code_model.options["package_mode"]:
|
|
121
|
+
self._serialize_and_write_package_files(namespace_path=namespace_path)
|
|
122
|
+
|
|
123
|
+
if (
|
|
124
|
+
self.code_model.options["show_operations"]
|
|
125
|
+
and self.code_model.has_operations
|
|
126
|
+
and self.code_model.options["generate_sample"]
|
|
127
|
+
):
|
|
128
|
+
self._serialize_and_write_sample(env, namespace_path)
|
|
129
|
+
|
|
130
|
+
if (
|
|
131
|
+
self.code_model.options["show_operations"]
|
|
132
|
+
and self.code_model.has_operations
|
|
133
|
+
and self.code_model.options["generate_test"]
|
|
134
|
+
):
|
|
135
|
+
self._serialize_and_write_test(env, namespace_path)
|
|
136
|
+
|
|
137
|
+
def serialize(self) -> None:
|
|
138
|
+
env = Environment(
|
|
139
|
+
loader=PackageLoader("pygen.codegen", "templates"),
|
|
140
|
+
keep_trailing_newline=True,
|
|
141
|
+
line_statement_prefix="##",
|
|
142
|
+
line_comment_prefix="###",
|
|
143
|
+
trim_blocks=True,
|
|
144
|
+
lstrip_blocks=True,
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
namespace_path = (
|
|
148
|
+
Path(".") if self.code_model.options["no_namespace_folders"] else Path(*self._name_space().split("."))
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
p = namespace_path.parent
|
|
152
|
+
general_serializer = GeneralSerializer(code_model=self.code_model, env=env, async_mode=False)
|
|
153
|
+
while p != Path("."):
|
|
154
|
+
# write pkgutil init file
|
|
155
|
+
self.write_file(
|
|
156
|
+
p / Path("__init__.py"),
|
|
157
|
+
general_serializer.serialize_pkgutil_init_file(),
|
|
158
|
+
)
|
|
159
|
+
p = p.parent
|
|
160
|
+
|
|
161
|
+
# serialize main module
|
|
162
|
+
self._serialize_namespace_level(
|
|
163
|
+
env,
|
|
164
|
+
namespace_path,
|
|
165
|
+
[c for c in self.code_model.clients if c.has_operations],
|
|
166
|
+
)
|
|
167
|
+
# serialize sub modules
|
|
168
|
+
for (
|
|
169
|
+
subnamespace,
|
|
170
|
+
clients,
|
|
171
|
+
) in self.code_model.subnamespace_to_clients.items():
|
|
172
|
+
subnamespace_path = namespace_path / Path(subnamespace)
|
|
173
|
+
self._serialize_namespace_level(env, subnamespace_path, [c for c in clients if c.has_operations])
|
|
174
|
+
|
|
175
|
+
if self.code_model.options["models_mode"] and (self.code_model.model_types or self.code_model.enums):
|
|
176
|
+
self._keep_patch_file(namespace_path / Path("models") / Path("_patch.py"), env)
|
|
177
|
+
|
|
178
|
+
if self.code_model.options["models_mode"] and (self.code_model.model_types or self.code_model.enums):
|
|
179
|
+
self._serialize_and_write_models_folder(env=env, namespace_path=namespace_path)
|
|
180
|
+
if not self.code_model.options["models_mode"]:
|
|
181
|
+
# keep models file if users ended up just writing a models file
|
|
182
|
+
if self.read_file(namespace_path / Path("models.py")):
|
|
183
|
+
self.write_file(
|
|
184
|
+
namespace_path / Path("models.py"),
|
|
185
|
+
self.read_file(namespace_path / Path("models.py")),
|
|
186
|
+
)
|
|
187
|
+
if self.code_model.named_unions:
|
|
188
|
+
self.write_file(
|
|
189
|
+
namespace_path / Path("_types.py"),
|
|
190
|
+
TypesSerializer(code_model=self.code_model, env=env).serialize(),
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
def _serialize_and_write_package_files(self, namespace_path: Path) -> None:
|
|
194
|
+
root_of_sdk = self._package_root_folder(namespace_path)
|
|
195
|
+
if self.code_model.options["package_mode"] in VALID_PACKAGE_MODE:
|
|
196
|
+
env = Environment(
|
|
197
|
+
loader=PackageLoader("pygen.codegen", "templates/packaging_templates"),
|
|
198
|
+
undefined=StrictUndefined,
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
package_files = _PACKAGE_FILES
|
|
202
|
+
elif Path(self.code_model.options["package_mode"]).exists():
|
|
203
|
+
env = Environment(
|
|
204
|
+
loader=FileSystemLoader(str(Path(self.code_model.options["package_mode"]))),
|
|
205
|
+
keep_trailing_newline=True,
|
|
206
|
+
undefined=StrictUndefined,
|
|
207
|
+
)
|
|
208
|
+
package_files = env.list_templates()
|
|
209
|
+
else:
|
|
210
|
+
return
|
|
211
|
+
serializer = GeneralSerializer(self.code_model, env, async_mode=False)
|
|
212
|
+
params = self.code_model.options["packaging_files_config"] or {}
|
|
213
|
+
for template_name in package_files:
|
|
214
|
+
if not self.code_model.is_azure_flavor and template_name == "dev_requirements.txt.jinja2":
|
|
215
|
+
continue
|
|
216
|
+
file = template_name.replace(".jinja2", "")
|
|
217
|
+
output_name = root_of_sdk / file
|
|
218
|
+
if not self.read_file(output_name) or file in _REGENERATE_FILES:
|
|
219
|
+
self.write_file(
|
|
220
|
+
output_name,
|
|
221
|
+
serializer.serialize_package_file(template_name, **params),
|
|
222
|
+
)
|
|
223
|
+
|
|
224
|
+
def _keep_patch_file(self, path_file: Path, env: Environment):
|
|
225
|
+
if self.read_file(path_file):
|
|
226
|
+
self.write_file(path_file, self.read_file(path_file))
|
|
227
|
+
else:
|
|
228
|
+
self.write_file(
|
|
229
|
+
path_file,
|
|
230
|
+
PatchSerializer(env=env, code_model=self.code_model).serialize(),
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
def _serialize_and_write_models_folder(self, env: Environment, namespace_path: Path) -> None:
|
|
234
|
+
# Write the models folder
|
|
235
|
+
models_path = namespace_path / Path("models")
|
|
236
|
+
serializer = DpgModelSerializer if self.code_model.options["models_mode"] == "dpg" else MsrestModelSerializer
|
|
237
|
+
if self.code_model.model_types:
|
|
238
|
+
self.write_file(
|
|
239
|
+
models_path / Path(f"{self.code_model.models_filename}.py"),
|
|
240
|
+
serializer(code_model=self.code_model, env=env).serialize(),
|
|
241
|
+
)
|
|
242
|
+
if self.code_model.enums:
|
|
243
|
+
self.write_file(
|
|
244
|
+
models_path / Path(f"{self.code_model.enums_filename}.py"),
|
|
245
|
+
EnumSerializer(code_model=self.code_model, env=env).serialize(),
|
|
246
|
+
)
|
|
247
|
+
self.write_file(
|
|
248
|
+
models_path / Path("__init__.py"),
|
|
249
|
+
ModelInitSerializer(code_model=self.code_model, env=env).serialize(),
|
|
250
|
+
)
|
|
251
|
+
|
|
252
|
+
def _serialize_and_write_rest_layer(self, env: Environment, namespace_path: Path) -> None:
|
|
253
|
+
rest_path = namespace_path / Path(self.code_model.rest_layer_name)
|
|
254
|
+
group_names = {rb.group_name for c in self.code_model.clients for rb in c.request_builders}
|
|
255
|
+
|
|
256
|
+
for group_name in group_names:
|
|
257
|
+
request_builders = [
|
|
258
|
+
r for c in self.code_model.clients for r in c.request_builders if r.group_name == group_name
|
|
259
|
+
]
|
|
260
|
+
self._serialize_and_write_single_rest_layer(env, rest_path, request_builders)
|
|
261
|
+
if not "" in group_names:
|
|
262
|
+
self.write_file(
|
|
263
|
+
rest_path / Path("__init__.py"),
|
|
264
|
+
self.code_model.options["license_header"],
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
def _serialize_and_write_single_rest_layer(
|
|
268
|
+
self,
|
|
269
|
+
env: Environment,
|
|
270
|
+
rest_path: Path,
|
|
271
|
+
request_builders: List[Union[RequestBuilder, OverloadedRequestBuilder]],
|
|
272
|
+
) -> None:
|
|
273
|
+
group_name = request_builders[0].group_name
|
|
274
|
+
output_path = rest_path / Path(group_name) if group_name else rest_path
|
|
275
|
+
# write generic request builders file
|
|
276
|
+
self.write_file(
|
|
277
|
+
output_path / Path("_request_builders.py"),
|
|
278
|
+
RequestBuildersSerializer(
|
|
279
|
+
code_model=self.code_model,
|
|
280
|
+
env=env,
|
|
281
|
+
request_builders=request_builders,
|
|
282
|
+
).serialize_request_builders(),
|
|
283
|
+
)
|
|
284
|
+
|
|
285
|
+
# write rest init file
|
|
286
|
+
self.write_file(
|
|
287
|
+
output_path / Path("__init__.py"),
|
|
288
|
+
RequestBuildersSerializer(
|
|
289
|
+
code_model=self.code_model,
|
|
290
|
+
env=env,
|
|
291
|
+
request_builders=request_builders,
|
|
292
|
+
).serialize_init(),
|
|
293
|
+
)
|
|
294
|
+
|
|
295
|
+
def _serialize_and_write_operations_file(
|
|
296
|
+
self,
|
|
297
|
+
env: Environment,
|
|
298
|
+
clients: List[Client],
|
|
299
|
+
namespace_path: Path,
|
|
300
|
+
operation_group: Optional[OperationGroup] = None,
|
|
301
|
+
) -> None:
|
|
302
|
+
filename = operation_group.filename if operation_group else "_operations"
|
|
303
|
+
# write first sync file
|
|
304
|
+
operation_group_serializer = OperationGroupsSerializer(
|
|
305
|
+
code_model=self.code_model,
|
|
306
|
+
clients=clients,
|
|
307
|
+
env=env,
|
|
308
|
+
async_mode=False,
|
|
309
|
+
operation_group=operation_group,
|
|
310
|
+
)
|
|
311
|
+
self.write_file(
|
|
312
|
+
namespace_path / Path(self.code_model.operations_folder_name) / Path(f"{filename}.py"),
|
|
313
|
+
operation_group_serializer.serialize(),
|
|
314
|
+
)
|
|
315
|
+
|
|
316
|
+
if self.has_aio_folder:
|
|
317
|
+
# write async operation group and operation files
|
|
318
|
+
operation_group_async_serializer = OperationGroupsSerializer(
|
|
319
|
+
code_model=self.code_model,
|
|
320
|
+
clients=clients,
|
|
321
|
+
env=env,
|
|
322
|
+
async_mode=True,
|
|
323
|
+
operation_group=operation_group,
|
|
324
|
+
)
|
|
325
|
+
self.write_file(
|
|
326
|
+
(namespace_path / Path("aio") / Path(self.code_model.operations_folder_name) / Path(f"{filename}.py")),
|
|
327
|
+
operation_group_async_serializer.serialize(),
|
|
328
|
+
)
|
|
329
|
+
|
|
330
|
+
def _serialize_and_write_operations_folder(
|
|
331
|
+
self, clients: List[Client], env: Environment, namespace_path: Path
|
|
332
|
+
) -> None:
|
|
333
|
+
# write sync operations init file
|
|
334
|
+
operations_init_serializer = OperationsInitSerializer(
|
|
335
|
+
code_model=self.code_model, clients=clients, env=env, async_mode=False
|
|
336
|
+
)
|
|
337
|
+
self.write_file(
|
|
338
|
+
namespace_path / Path(self.code_model.operations_folder_name) / Path("__init__.py"),
|
|
339
|
+
operations_init_serializer.serialize(),
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
# write async operations init file
|
|
343
|
+
if self.has_aio_folder:
|
|
344
|
+
operations_async_init_serializer = OperationsInitSerializer(
|
|
345
|
+
code_model=self.code_model, clients=clients, env=env, async_mode=True
|
|
346
|
+
)
|
|
347
|
+
self.write_file(
|
|
348
|
+
namespace_path / Path("aio") / Path(self.code_model.operations_folder_name) / Path("__init__.py"),
|
|
349
|
+
operations_async_init_serializer.serialize(),
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
if self.code_model.options["combine_operation_files"]:
|
|
353
|
+
self._serialize_and_write_operations_file(
|
|
354
|
+
env=env,
|
|
355
|
+
namespace_path=namespace_path,
|
|
356
|
+
clients=clients,
|
|
357
|
+
)
|
|
358
|
+
else:
|
|
359
|
+
for operation_group in get_all_operation_groups_recursively(self.code_model.clients):
|
|
360
|
+
self._serialize_and_write_operations_file(
|
|
361
|
+
env=env,
|
|
362
|
+
namespace_path=namespace_path,
|
|
363
|
+
operation_group=operation_group,
|
|
364
|
+
clients=clients,
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
def _serialize_and_write_version_file(
|
|
368
|
+
self,
|
|
369
|
+
namespace_path: Path,
|
|
370
|
+
general_serializer: GeneralSerializer,
|
|
371
|
+
):
|
|
372
|
+
def _read_version_file(original_version_file_name: str) -> str:
|
|
373
|
+
return self.read_file(namespace_path / original_version_file_name)
|
|
374
|
+
|
|
375
|
+
def _write_version_file(original_version_file_name: str) -> None:
|
|
376
|
+
self.write_file(
|
|
377
|
+
namespace_path / Path("_version.py"),
|
|
378
|
+
_read_version_file(original_version_file_name),
|
|
379
|
+
)
|
|
380
|
+
|
|
381
|
+
keep_version_file = self.code_model.options["keep_version_file"]
|
|
382
|
+
if keep_version_file and _read_version_file("_version.py"):
|
|
383
|
+
_write_version_file(original_version_file_name="_version.py")
|
|
384
|
+
elif keep_version_file and _read_version_file("version.py"):
|
|
385
|
+
_write_version_file(original_version_file_name="version.py")
|
|
386
|
+
elif self.code_model.options["package_version"]:
|
|
387
|
+
self.write_file(
|
|
388
|
+
namespace_path / Path("_version.py"),
|
|
389
|
+
general_serializer.serialize_version_file(),
|
|
390
|
+
)
|
|
391
|
+
|
|
392
|
+
def _serialize_client_and_config_files(
|
|
393
|
+
self,
|
|
394
|
+
namespace_path: Path,
|
|
395
|
+
general_serializer: GeneralSerializer,
|
|
396
|
+
async_mode: bool,
|
|
397
|
+
clients: List[Client],
|
|
398
|
+
) -> None:
|
|
399
|
+
if self.code_model.has_operations:
|
|
400
|
+
namespace_path = namespace_path / Path("aio") if async_mode else namespace_path
|
|
401
|
+
self.write_file(
|
|
402
|
+
namespace_path / Path(f"{self.code_model.client_filename}.py"),
|
|
403
|
+
general_serializer.serialize_service_client_file(clients),
|
|
404
|
+
)
|
|
405
|
+
self.write_file(
|
|
406
|
+
namespace_path / Path("_configuration.py"),
|
|
407
|
+
general_serializer.serialize_config_file(clients),
|
|
408
|
+
)
|
|
409
|
+
|
|
410
|
+
def _serialize_and_write_top_level_folder(
|
|
411
|
+
self, env: Environment, namespace_path: Path, clients: List[Client]
|
|
412
|
+
) -> None:
|
|
413
|
+
general_serializer = GeneralSerializer(code_model=self.code_model, env=env, async_mode=False)
|
|
414
|
+
|
|
415
|
+
self.write_file(
|
|
416
|
+
namespace_path / Path("__init__.py"),
|
|
417
|
+
general_serializer.serialize_init_file(clients),
|
|
418
|
+
)
|
|
419
|
+
|
|
420
|
+
# Write the service client
|
|
421
|
+
self._serialize_client_and_config_files(namespace_path, general_serializer, async_mode=False, clients=clients)
|
|
422
|
+
if self.code_model.need_vendored_code(async_mode=False):
|
|
423
|
+
self.write_file(
|
|
424
|
+
namespace_path / Path("_vendor.py"),
|
|
425
|
+
general_serializer.serialize_vendor_file(clients),
|
|
426
|
+
)
|
|
427
|
+
|
|
428
|
+
self._serialize_and_write_version_file(namespace_path, general_serializer)
|
|
429
|
+
|
|
430
|
+
# write the empty py.typed file
|
|
431
|
+
self.write_file(namespace_path / Path("py.typed"), "# Marker file for PEP 561.")
|
|
432
|
+
|
|
433
|
+
if not self.code_model.options["client_side_validation"] and not self.code_model.options["multiapi"]:
|
|
434
|
+
self.write_file(
|
|
435
|
+
namespace_path / Path("_serialization.py"),
|
|
436
|
+
general_serializer.serialize_serialization_file(),
|
|
437
|
+
)
|
|
438
|
+
if self.code_model.options["models_mode"] == "dpg":
|
|
439
|
+
self.write_file(
|
|
440
|
+
namespace_path / Path("_model_base.py"),
|
|
441
|
+
general_serializer.serialize_model_base_file(),
|
|
442
|
+
)
|
|
443
|
+
|
|
444
|
+
if any(og for client in self.code_model.clients for og in client.operation_groups if og.need_validation):
|
|
445
|
+
self.write_file(
|
|
446
|
+
namespace_path / Path("_validation.py"),
|
|
447
|
+
general_serializer.serialize_validation_file(),
|
|
448
|
+
)
|
|
449
|
+
if self.code_model.options.get("emit_cross_language_definition_file"):
|
|
450
|
+
self.write_file(
|
|
451
|
+
Path("./apiview_mapping_python.json"),
|
|
452
|
+
general_serializer.serialize_cross_language_definition_file(),
|
|
453
|
+
)
|
|
454
|
+
|
|
455
|
+
# Write the setup file
|
|
456
|
+
if self.code_model.options["basic_setup_py"]:
|
|
457
|
+
self.write_file(Path("setup.py"), general_serializer.serialize_setup_file())
|
|
458
|
+
|
|
459
|
+
def _serialize_and_write_aio_top_level_folder(
|
|
460
|
+
self, env: Environment, namespace_path: Path, clients: List[Client]
|
|
461
|
+
) -> None:
|
|
462
|
+
aio_general_serializer = GeneralSerializer(code_model=self.code_model, env=env, async_mode=True)
|
|
463
|
+
|
|
464
|
+
aio_path = namespace_path / Path("aio")
|
|
465
|
+
|
|
466
|
+
# Write the __init__ file
|
|
467
|
+
self.write_file(
|
|
468
|
+
aio_path / Path("__init__.py"),
|
|
469
|
+
aio_general_serializer.serialize_init_file(clients),
|
|
470
|
+
)
|
|
471
|
+
|
|
472
|
+
# Write the service client
|
|
473
|
+
self._serialize_client_and_config_files(
|
|
474
|
+
namespace_path, aio_general_serializer, async_mode=True, clients=clients
|
|
475
|
+
)
|
|
476
|
+
if self.code_model.need_vendored_code(async_mode=True):
|
|
477
|
+
self.write_file(
|
|
478
|
+
aio_path / Path("_vendor.py"),
|
|
479
|
+
aio_general_serializer.serialize_vendor_file(clients),
|
|
480
|
+
)
|
|
481
|
+
|
|
482
|
+
def _serialize_and_write_metadata(self, env: Environment, namespace_path: Path) -> None:
|
|
483
|
+
metadata_serializer = MetadataSerializer(self.code_model, env)
|
|
484
|
+
self.write_file(namespace_path / Path("_metadata.json"), metadata_serializer.serialize())
|
|
485
|
+
|
|
486
|
+
@property
|
|
487
|
+
def _namespace_from_package_name(self) -> str:
|
|
488
|
+
return get_namespace_from_package_name(self.code_model.options["package_name"])
|
|
489
|
+
|
|
490
|
+
def _name_space(self) -> str:
|
|
491
|
+
if self.code_model.namespace.count(".") >= self._namespace_from_package_name.count("."):
|
|
492
|
+
return self.code_model.namespace
|
|
493
|
+
|
|
494
|
+
return self._namespace_from_package_name
|
|
495
|
+
|
|
496
|
+
# find root folder where "setup.py" is
|
|
497
|
+
def _package_root_folder(self, namespace_path: Path) -> Path:
|
|
498
|
+
return namespace_path / Path("../" * (self._name_space().count(".") + 1))
|
|
499
|
+
|
|
500
|
+
@property
|
|
501
|
+
def _additional_folder(self) -> Path:
|
|
502
|
+
namespace_config = get_namespace_config(self.code_model.namespace, self.code_model.options["multiapi"])
|
|
503
|
+
num_of_namespace = namespace_config.count(".") + 1
|
|
504
|
+
num_of_package_namespace = self._namespace_from_package_name.count(".") + 1
|
|
505
|
+
if num_of_namespace > num_of_package_namespace:
|
|
506
|
+
return Path("/".join(namespace_config.split(".")[num_of_package_namespace:]))
|
|
507
|
+
return Path("")
|
|
508
|
+
|
|
509
|
+
def _serialize_and_write_sample(self, env: Environment, namespace_path: Path):
|
|
510
|
+
out_path = self._package_root_folder(namespace_path) / Path("generated_samples")
|
|
511
|
+
for client in self.code_model.clients:
|
|
512
|
+
for op_group in client.operation_groups:
|
|
513
|
+
for operation in op_group.operations:
|
|
514
|
+
if (
|
|
515
|
+
self.code_model.options["multiapi"]
|
|
516
|
+
and operation.api_versions[0] != self.code_model.options["default_api_version"]
|
|
517
|
+
):
|
|
518
|
+
continue
|
|
519
|
+
samples = operation.yaml_data.get("samples")
|
|
520
|
+
if not samples or operation.name.startswith("_"):
|
|
521
|
+
continue
|
|
522
|
+
for value in samples.values():
|
|
523
|
+
file = value.get("x-ms-original-file", "sample.json")
|
|
524
|
+
file_name = to_snake_case(extract_sample_name(file)) + ".py"
|
|
525
|
+
try:
|
|
526
|
+
self.write_file(
|
|
527
|
+
out_path / self._additional_folder / _sample_output_path(file) / file_name,
|
|
528
|
+
SampleSerializer(
|
|
529
|
+
code_model=self.code_model,
|
|
530
|
+
env=env,
|
|
531
|
+
operation_group=op_group,
|
|
532
|
+
operation=operation,
|
|
533
|
+
sample=value,
|
|
534
|
+
file_name=file_name,
|
|
535
|
+
).serialize(),
|
|
536
|
+
)
|
|
537
|
+
except Exception as e: # pylint: disable=broad-except
|
|
538
|
+
# sample generation shall not block code generation, so just log error
|
|
539
|
+
log_error = f"error happens in sample {file}: {e}"
|
|
540
|
+
_LOGGER.error(log_error)
|
|
541
|
+
|
|
542
|
+
def _serialize_and_write_test(self, env: Environment, namespace_path: Path):
|
|
543
|
+
self.code_model.for_test = True
|
|
544
|
+
out_path = self._package_root_folder(namespace_path) / Path("generated_tests")
|
|
545
|
+
general_serializer = TestGeneralSerializer(code_model=self.code_model, env=env)
|
|
546
|
+
self.write_file(out_path / "conftest.py", general_serializer.serialize_conftest())
|
|
547
|
+
if not self.code_model.options["azure_arm"]:
|
|
548
|
+
for is_async in (True, False):
|
|
549
|
+
async_suffix = "_async" if is_async else ""
|
|
550
|
+
general_serializer.is_async = is_async
|
|
551
|
+
self.write_file(
|
|
552
|
+
out_path / f"testpreparer{async_suffix}.py",
|
|
553
|
+
general_serializer.serialize_testpreparer(),
|
|
554
|
+
)
|
|
555
|
+
|
|
556
|
+
for client in self.code_model.clients:
|
|
557
|
+
for og in client.operation_groups:
|
|
558
|
+
if self.code_model.options["multiapi"] and any(
|
|
559
|
+
o.api_versions[0] != self.code_model.options["default_api_version"] for o in og.operations
|
|
560
|
+
):
|
|
561
|
+
continue
|
|
562
|
+
test_serializer = TestSerializer(self.code_model, env, client=client, operation_group=og)
|
|
563
|
+
for is_async in (True, False):
|
|
564
|
+
try:
|
|
565
|
+
test_serializer.is_async = is_async
|
|
566
|
+
self.write_file(
|
|
567
|
+
out_path / f"{to_snake_case(test_serializer.test_class_name)}.py",
|
|
568
|
+
test_serializer.serialize_test(),
|
|
569
|
+
)
|
|
570
|
+
except Exception as e: # pylint: disable=broad-except
|
|
571
|
+
# test generation shall not block code generation, so just log error
|
|
572
|
+
log_error = f"error happens in test generation for operation group {og.class_name}: {e}"
|
|
573
|
+
_LOGGER.error(log_error)
|
|
574
|
+
self.code_model.for_test = False
|
|
@@ -0,0 +1,21 @@
|
|
|
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 jinja2 import Environment
|
|
7
|
+
from ..models import (
|
|
8
|
+
FileImport,
|
|
9
|
+
CodeModel,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BaseSerializer:
|
|
14
|
+
"""Base serializer for SDK root level files"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, code_model: CodeModel, env: Environment):
|
|
17
|
+
self.code_model = code_model
|
|
18
|
+
self.env = env
|
|
19
|
+
|
|
20
|
+
def init_file_import(self) -> FileImport:
|
|
21
|
+
return FileImport(self.code_model)
|