@autorest/python 6.27.4 → 6.28.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.
Files changed (114) hide show
  1. package/generator/build/lib/pygen/black.py +3 -3
  2. package/generator/build/lib/pygen/codegen/__init__.py +2 -0
  3. package/generator/build/lib/pygen/codegen/_utils.py +4 -0
  4. package/generator/build/lib/pygen/codegen/models/base.py +2 -3
  5. package/generator/build/lib/pygen/codegen/models/base_builder.py +5 -3
  6. package/generator/build/lib/pygen/codegen/models/client.py +28 -19
  7. package/generator/build/lib/pygen/codegen/models/code_model.py +200 -33
  8. package/generator/build/lib/pygen/codegen/models/combined_type.py +8 -5
  9. package/generator/build/lib/pygen/codegen/models/constant_type.py +2 -3
  10. package/generator/build/lib/pygen/codegen/models/credential_types.py +2 -3
  11. package/generator/build/lib/pygen/codegen/models/dictionary_type.py +2 -3
  12. package/generator/build/lib/pygen/codegen/models/enum_type.py +47 -24
  13. package/generator/build/lib/pygen/codegen/models/imports.py +14 -12
  14. package/generator/build/lib/pygen/codegen/models/list_type.py +2 -3
  15. package/generator/build/lib/pygen/codegen/models/lro_operation.py +8 -4
  16. package/generator/build/lib/pygen/codegen/models/lro_paging_operation.py +2 -2
  17. package/generator/build/lib/pygen/codegen/models/model_type.py +34 -19
  18. package/generator/build/lib/pygen/codegen/models/operation.py +66 -29
  19. package/generator/build/lib/pygen/codegen/models/operation_group.py +56 -11
  20. package/generator/build/lib/pygen/codegen/models/paging_operation.py +9 -6
  21. package/generator/build/lib/pygen/codegen/models/parameter.py +10 -10
  22. package/generator/build/lib/pygen/codegen/models/parameter_list.py +7 -7
  23. package/generator/build/lib/pygen/codegen/models/primitive_types.py +23 -43
  24. package/generator/build/lib/pygen/codegen/models/property.py +7 -7
  25. package/generator/build/lib/pygen/codegen/models/request_builder.py +9 -15
  26. package/generator/build/lib/pygen/codegen/models/response.py +6 -8
  27. package/generator/build/lib/pygen/codegen/models/utils.py +11 -0
  28. package/generator/build/lib/pygen/codegen/serializers/__init__.py +219 -244
  29. package/generator/build/lib/pygen/codegen/serializers/base_serializer.py +19 -1
  30. package/generator/build/lib/pygen/codegen/serializers/builder_serializer.py +53 -35
  31. package/generator/build/lib/pygen/codegen/serializers/client_serializer.py +9 -5
  32. package/generator/build/lib/pygen/codegen/serializers/enum_serializer.py +17 -3
  33. package/generator/build/lib/pygen/codegen/serializers/general_serializer.py +26 -14
  34. package/generator/build/lib/pygen/codegen/serializers/metadata_serializer.py +26 -8
  35. package/generator/build/lib/pygen/codegen/serializers/model_init_serializer.py +9 -4
  36. package/generator/build/lib/pygen/codegen/serializers/model_serializer.py +63 -23
  37. package/generator/build/lib/pygen/codegen/serializers/operation_groups_serializer.py +19 -16
  38. package/generator/build/lib/pygen/codegen/serializers/operations_init_serializer.py +5 -10
  39. package/generator/build/lib/pygen/codegen/serializers/parameter_serializer.py +10 -7
  40. package/generator/build/lib/pygen/codegen/serializers/request_builders_serializer.py +10 -1
  41. package/generator/build/lib/pygen/codegen/serializers/sample_serializer.py +7 -10
  42. package/generator/build/lib/pygen/codegen/serializers/test_serializer.py +24 -28
  43. package/generator/build/lib/pygen/codegen/serializers/types_serializer.py +6 -1
  44. package/generator/build/lib/pygen/codegen/serializers/utils.py +1 -15
  45. package/generator/build/lib/pygen/codegen/templates/client_container.py.jinja2 +1 -1
  46. package/generator/build/lib/pygen/codegen/templates/config_container.py.jinja2 +1 -1
  47. package/generator/build/lib/pygen/codegen/templates/enum_container.py.jinja2 +1 -1
  48. package/generator/build/lib/pygen/codegen/templates/init.py.jinja2 +1 -1
  49. package/generator/build/lib/pygen/codegen/templates/model_container.py.jinja2 +1 -1
  50. package/generator/build/lib/pygen/codegen/templates/operations_folder_init.py.jinja2 +2 -4
  51. package/generator/build/lib/pygen/codegen/templates/test.py.jinja2 +3 -3
  52. package/generator/build/lib/pygen/codegen/templates/testpreparer.py.jinja2 +2 -2
  53. package/generator/build/lib/pygen/codegen/templates/vendor.py.jinja2 +4 -4
  54. package/generator/build/lib/pygen/preprocess/__init__.py +0 -4
  55. package/generator/component-detection-pip-report.json +2 -2
  56. package/generator/dev_requirements.txt +2 -2
  57. package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
  58. package/generator/pygen/black.py +3 -3
  59. package/generator/pygen/codegen/__init__.py +2 -0
  60. package/generator/pygen/codegen/_utils.py +4 -0
  61. package/generator/pygen/codegen/models/base.py +2 -3
  62. package/generator/pygen/codegen/models/base_builder.py +5 -3
  63. package/generator/pygen/codegen/models/client.py +28 -19
  64. package/generator/pygen/codegen/models/code_model.py +200 -33
  65. package/generator/pygen/codegen/models/combined_type.py +8 -5
  66. package/generator/pygen/codegen/models/constant_type.py +2 -3
  67. package/generator/pygen/codegen/models/credential_types.py +2 -3
  68. package/generator/pygen/codegen/models/dictionary_type.py +2 -3
  69. package/generator/pygen/codegen/models/enum_type.py +47 -24
  70. package/generator/pygen/codegen/models/imports.py +14 -12
  71. package/generator/pygen/codegen/models/list_type.py +2 -3
  72. package/generator/pygen/codegen/models/lro_operation.py +8 -4
  73. package/generator/pygen/codegen/models/lro_paging_operation.py +2 -2
  74. package/generator/pygen/codegen/models/model_type.py +34 -19
  75. package/generator/pygen/codegen/models/operation.py +66 -29
  76. package/generator/pygen/codegen/models/operation_group.py +56 -11
  77. package/generator/pygen/codegen/models/paging_operation.py +9 -6
  78. package/generator/pygen/codegen/models/parameter.py +10 -10
  79. package/generator/pygen/codegen/models/parameter_list.py +7 -7
  80. package/generator/pygen/codegen/models/primitive_types.py +23 -43
  81. package/generator/pygen/codegen/models/property.py +7 -7
  82. package/generator/pygen/codegen/models/request_builder.py +9 -15
  83. package/generator/pygen/codegen/models/response.py +6 -8
  84. package/generator/pygen/codegen/models/utils.py +11 -0
  85. package/generator/pygen/codegen/serializers/__init__.py +219 -244
  86. package/generator/pygen/codegen/serializers/base_serializer.py +19 -1
  87. package/generator/pygen/codegen/serializers/builder_serializer.py +53 -35
  88. package/generator/pygen/codegen/serializers/client_serializer.py +9 -5
  89. package/generator/pygen/codegen/serializers/enum_serializer.py +17 -3
  90. package/generator/pygen/codegen/serializers/general_serializer.py +26 -14
  91. package/generator/pygen/codegen/serializers/metadata_serializer.py +26 -8
  92. package/generator/pygen/codegen/serializers/model_init_serializer.py +9 -4
  93. package/generator/pygen/codegen/serializers/model_serializer.py +63 -23
  94. package/generator/pygen/codegen/serializers/operation_groups_serializer.py +19 -16
  95. package/generator/pygen/codegen/serializers/operations_init_serializer.py +5 -10
  96. package/generator/pygen/codegen/serializers/parameter_serializer.py +10 -7
  97. package/generator/pygen/codegen/serializers/request_builders_serializer.py +10 -1
  98. package/generator/pygen/codegen/serializers/sample_serializer.py +7 -10
  99. package/generator/pygen/codegen/serializers/test_serializer.py +24 -28
  100. package/generator/pygen/codegen/serializers/types_serializer.py +6 -1
  101. package/generator/pygen/codegen/serializers/utils.py +1 -15
  102. package/generator/pygen/codegen/templates/client_container.py.jinja2 +1 -1
  103. package/generator/pygen/codegen/templates/config_container.py.jinja2 +1 -1
  104. package/generator/pygen/codegen/templates/enum_container.py.jinja2 +1 -1
  105. package/generator/pygen/codegen/templates/init.py.jinja2 +1 -1
  106. package/generator/pygen/codegen/templates/model_container.py.jinja2 +1 -1
  107. package/generator/pygen/codegen/templates/operations_folder_init.py.jinja2 +2 -4
  108. package/generator/pygen/codegen/templates/test.py.jinja2 +3 -3
  109. package/generator/pygen/codegen/templates/testpreparer.py.jinja2 +2 -2
  110. package/generator/pygen/codegen/templates/vendor.py.jinja2 +4 -4
  111. package/generator/pygen/preprocess/__init__.py +0 -4
  112. package/generator/pygen.egg-info/PKG-INFO +10 -1
  113. package/package.json +2 -2
  114. package/scripts/__pycache__/venvtools.cpython-310.pyc +0 -0
@@ -4,7 +4,9 @@
4
4
  # license information.
5
5
  # --------------------------------------------------------------------------
6
6
  import logging
7
- from typing import List, Optional, Any, Union
7
+ from collections import namedtuple
8
+ import re
9
+ from typing import List, Any, Union
8
10
  from pathlib import Path
9
11
  from jinja2 import PackageLoader, Environment, FileSystemLoader, StrictUndefined
10
12
 
@@ -15,6 +17,8 @@ from ..models import (
15
17
  OverloadedRequestBuilder,
16
18
  CodeModel,
17
19
  Client,
20
+ ModelType,
21
+ EnumType,
18
22
  )
19
23
  from .enum_serializer import EnumSerializer
20
24
  from .general_serializer import GeneralSerializer
@@ -34,7 +38,6 @@ from .utils import (
34
38
  extract_sample_name,
35
39
  get_namespace_from_package_name,
36
40
  get_namespace_config,
37
- get_all_operation_groups_recursively,
38
41
  )
39
42
 
40
43
  _LOGGER = logging.getLogger(__name__)
@@ -53,6 +56,7 @@ _PACKAGE_FILES = [
53
56
  ]
54
57
 
55
58
  _REGENERATE_FILES = {"setup.py", "MANIFEST.in"}
59
+ AsyncInfo = namedtuple("AsyncInfo", ["async_mode", "async_path"])
56
60
 
57
61
 
58
62
  # extract sub folders. For example, source_file_path is like:
@@ -85,54 +89,24 @@ class JinjaSerializer(ReaderAndWriter):
85
89
  def has_operations_folder(self) -> bool:
86
90
  return self.code_model.options["show_operations"] and bool(self.code_model.has_operations)
87
91
 
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
- )
92
+ @property
93
+ def serialize_loop(self) -> List[AsyncInfo]:
94
+ sync_loop = AsyncInfo(async_mode=False, async_path="")
95
+ async_loop = AsyncInfo(async_mode=True, async_path="aio/")
96
+ return [sync_loop, async_loop] if self.has_aio_folder else [sync_loop]
115
97
 
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)
98
+ @property
99
+ def keep_version_file(self) -> bool:
100
+ if self.options.get("keep_version_file"):
101
+ return True
102
+ # If the version file is already there and the version is greater than the current version, keep it.
103
+ try:
104
+ serialized_version_file = self.read_file(self.exec_path(self.code_model.namespace) / "_version.py")
105
+ match = re.search(r'VERSION\s*=\s*"([^"]+)"', str(serialized_version_file))
106
+ serialized_version = match.group(1) if match else ""
107
+ except (FileNotFoundError, IndexError):
108
+ serialized_version = ""
109
+ return serialized_version > self.code_model.options["package_version"]
136
110
 
137
111
  def serialize(self) -> None:
138
112
  env = Environment(
@@ -144,54 +118,71 @@ class JinjaSerializer(ReaderAndWriter):
144
118
  lstrip_blocks=True,
145
119
  )
146
120
 
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
121
  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")):
122
+ for client_namespace, client_namespace_type in self.code_model.client_namespace_types.items():
123
+ exec_path = self.exec_path(client_namespace)
124
+ if client_namespace == "":
125
+ # Write the setup file
126
+ if self.code_model.options["basic_setup_py"]:
127
+ self.write_file(exec_path / Path("setup.py"), general_serializer.serialize_setup_file())
128
+
129
+ # add packaging files in root namespace (e.g. setup.py, README.md, etc.)
130
+ if self.code_model.options["package_mode"]:
131
+ self._serialize_and_write_package_files(client_namespace)
132
+
133
+ # write apiview_mapping_python.json
134
+ if self.code_model.options.get("emit_cross_language_definition_file"):
135
+ self.write_file(
136
+ exec_path / Path("apiview_mapping_python.json"),
137
+ general_serializer.serialize_cross_language_definition_file(),
138
+ )
139
+
140
+ # add generated samples and generated tests
141
+ if self.code_model.options["show_operations"] and self.code_model.has_operations:
142
+ if self.code_model.options["generate_sample"]:
143
+ self._serialize_and_write_sample(env, namespace=client_namespace)
144
+ if self.code_model.options["generate_test"]:
145
+ self._serialize_and_write_test(env, namespace=client_namespace)
146
+ elif client_namespace_type.clients:
147
+ # add clients folder if there are clients in this namespace
148
+ self._serialize_client_and_config_files(client_namespace, client_namespace_type.clients, env)
149
+ else:
150
+ # add pkgutil init file if no clients in this namespace
183
151
  self.write_file(
184
- namespace_path / Path("models.py"),
185
- self.read_file(namespace_path / Path("models.py")),
152
+ exec_path / Path("__init__.py"),
153
+ general_serializer.serialize_pkgutil_init_file(),
186
154
  )
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
155
 
193
- def _serialize_and_write_package_files(self, namespace_path: Path) -> None:
194
- root_of_sdk = self._package_root_folder(namespace_path)
156
+ # _model_base.py/_serialization.py/_vendor.py/py.typed/_types.py/_validation.py
157
+ # is always put in top level namespace
158
+ if self.code_model.is_top_namespace(client_namespace):
159
+ self._serialize_and_write_top_level_folder(env=env, namespace=client_namespace)
160
+
161
+ # add models folder if there are models in this namespace
162
+ if (client_namespace_type.models or client_namespace_type.enums) and self.code_model.options["models_mode"]:
163
+ self._serialize_and_write_models_folder(
164
+ env=env,
165
+ namespace=client_namespace,
166
+ models=client_namespace_type.models,
167
+ enums=client_namespace_type.enums,
168
+ )
169
+
170
+ if not self.code_model.options["models_mode"]:
171
+ # keep models file if users ended up just writing a models file
172
+ model_path = exec_path / Path("models.py")
173
+ if self.read_file(model_path):
174
+ self.write_file(model_path, self.read_file(model_path))
175
+
176
+ # add operations folder if there are operations in this namespace
177
+ if client_namespace_type.operation_groups:
178
+ self._serialize_and_write_operations_folder(
179
+ client_namespace_type.operation_groups, env=env, namespace=client_namespace
180
+ )
181
+ if self.code_model.options["multiapi"]:
182
+ self._serialize_and_write_metadata(env=env, namespace=client_namespace)
183
+
184
+ def _serialize_and_write_package_files(self, client_namespace: str) -> None:
185
+ root_of_sdk = self.exec_path(client_namespace)
195
186
  if self.code_model.options["package_mode"] in VALID_PACKAGE_MODE:
196
187
  env = Environment(
197
188
  loader=PackageLoader("pygen.codegen", "templates/packaging_templates"),
@@ -216,6 +207,9 @@ class JinjaSerializer(ReaderAndWriter):
216
207
  file = template_name.replace(".jinja2", "")
217
208
  output_name = root_of_sdk / file
218
209
  if not self.read_file(output_name) or file in _REGENERATE_FILES:
210
+ if self.keep_version_file and file == "setup.py":
211
+ # don't regenerate setup.py file if the version file is more up to date
212
+ continue
219
213
  self.write_file(
220
214
  output_name,
221
215
  serializer.serialize_package_file(template_name, **params),
@@ -230,25 +224,31 @@ class JinjaSerializer(ReaderAndWriter):
230
224
  PatchSerializer(env=env, code_model=self.code_model).serialize(),
231
225
  )
232
226
 
233
- def _serialize_and_write_models_folder(self, env: Environment, namespace_path: Path) -> None:
227
+ def _serialize_and_write_models_folder(
228
+ self, env: Environment, namespace: str, models: List[ModelType], enums: List[EnumType]
229
+ ) -> None:
234
230
  # Write the models folder
235
- models_path = namespace_path / Path("models")
231
+ models_path = self.exec_path(namespace + ".models")
236
232
  serializer = DpgModelSerializer if self.code_model.options["models_mode"] == "dpg" else MsrestModelSerializer
237
- if self.code_model.model_types:
233
+ if models:
238
234
  self.write_file(
239
235
  models_path / Path(f"{self.code_model.models_filename}.py"),
240
- serializer(code_model=self.code_model, env=env).serialize(),
236
+ serializer(code_model=self.code_model, env=env, client_namespace=namespace, models=models).serialize(),
241
237
  )
242
- if self.code_model.enums:
238
+ if enums:
243
239
  self.write_file(
244
240
  models_path / Path(f"{self.code_model.enums_filename}.py"),
245
- EnumSerializer(code_model=self.code_model, env=env).serialize(),
241
+ EnumSerializer(
242
+ code_model=self.code_model, env=env, client_namespace=namespace, enums=enums
243
+ ).serialize(),
246
244
  )
247
245
  self.write_file(
248
246
  models_path / Path("__init__.py"),
249
- ModelInitSerializer(code_model=self.code_model, env=env).serialize(),
247
+ ModelInitSerializer(code_model=self.code_model, env=env, models=models, enums=enums).serialize(),
250
248
  )
251
249
 
250
+ self._keep_patch_file(models_path / Path("_patch.py"), env)
251
+
252
252
  def _serialize_and_write_rest_layer(self, env: Environment, namespace_path: Path) -> None:
253
253
  rest_path = namespace_path / Path(self.code_model.rest_layer_name)
254
254
  group_names = {rb.group_name for c in self.code_model.clients for rb in c.request_builders}
@@ -292,196 +292,163 @@ class JinjaSerializer(ReaderAndWriter):
292
292
  ).serialize_init(),
293
293
  )
294
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
295
  def _serialize_and_write_operations_folder(
331
- self, clients: List[Client], env: Environment, namespace_path: Path
296
+ self, operation_groups: List[OperationGroup], env: Environment, namespace: str
332
297
  ) -> 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
298
+ operations_folder_name = self.code_model.operations_folder_name(namespace)
299
+ exec_path = self.exec_path(namespace)
300
+ for async_mode, async_path in self.serialize_loop:
301
+ prefix_path = f"{async_path}{operations_folder_name}"
302
+ # write init file
303
+ operations_init_serializer = OperationsInitSerializer(
304
+ code_model=self.code_model, operation_groups=operation_groups, env=env, async_mode=async_mode
346
305
  )
347
306
  self.write_file(
348
- namespace_path / Path("aio") / Path(self.code_model.operations_folder_name) / Path("__init__.py"),
349
- operations_async_init_serializer.serialize(),
307
+ exec_path / Path(f"{prefix_path}/__init__.py"),
308
+ operations_init_serializer.serialize(),
350
309
  )
351
310
 
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(
311
+ # write operations file
312
+ OgLoop = namedtuple("OgLoop", ["operation_groups", "filename"])
313
+ if self.code_model.options["combine_operation_files"]:
314
+ loops = [OgLoop(operation_groups, "_operations")]
315
+ else:
316
+ loops = [OgLoop([og], og.filename) for og in operation_groups]
317
+ for ogs, filename in loops:
318
+ operation_group_serializer = OperationGroupsSerializer(
319
+ code_model=self.code_model,
320
+ operation_groups=ogs,
361
321
  env=env,
362
- namespace_path=namespace_path,
363
- operation_group=operation_group,
364
- clients=clients,
322
+ async_mode=async_mode,
323
+ client_namespace=namespace,
324
+ )
325
+ self.write_file(
326
+ exec_path / Path(f"{prefix_path}/{filename}.py"),
327
+ operation_group_serializer.serialize(),
365
328
  )
366
329
 
330
+ # if there was a patch file before, we keep it
331
+ self._keep_patch_file(exec_path / Path(f"{prefix_path}/_patch.py"), env)
332
+
367
333
  def _serialize_and_write_version_file(
368
334
  self,
369
- namespace_path: Path,
335
+ namespace: str,
370
336
  general_serializer: GeneralSerializer,
371
337
  ):
338
+ exec_path = self.exec_path(namespace)
339
+
372
340
  def _read_version_file(original_version_file_name: str) -> str:
373
- return self.read_file(namespace_path / original_version_file_name)
341
+ return self.read_file(exec_path / original_version_file_name)
374
342
 
375
343
  def _write_version_file(original_version_file_name: str) -> None:
376
344
  self.write_file(
377
- namespace_path / Path("_version.py"),
345
+ exec_path / Path("_version.py"),
378
346
  _read_version_file(original_version_file_name),
379
347
  )
380
348
 
381
- keep_version_file = self.code_model.options["keep_version_file"]
382
- if keep_version_file and _read_version_file("_version.py"):
349
+ if self.keep_version_file and _read_version_file("_version.py"):
383
350
  _write_version_file(original_version_file_name="_version.py")
384
- elif keep_version_file and _read_version_file("version.py"):
351
+ elif self.keep_version_file and _read_version_file("version.py"):
385
352
  _write_version_file(original_version_file_name="version.py")
386
353
  elif self.code_model.options["package_version"]:
387
354
  self.write_file(
388
- namespace_path / Path("_version.py"),
355
+ exec_path / Path("_version.py"),
389
356
  general_serializer.serialize_version_file(),
390
357
  )
391
358
 
392
359
  def _serialize_client_and_config_files(
393
360
  self,
394
- namespace_path: Path,
395
- general_serializer: GeneralSerializer,
396
- async_mode: bool,
361
+ namespace: str,
397
362
  clients: List[Client],
363
+ env: Environment,
398
364
  ) -> 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),
365
+ exec_path = self.exec_path(namespace)
366
+ for async_mode, async_path in self.serialize_loop:
367
+ general_serializer = GeneralSerializer(
368
+ code_model=self.code_model, env=env, async_mode=async_mode, client_namespace=namespace
404
369
  )
370
+ # when there is client.py, there must be __init__.py
405
371
  self.write_file(
406
- namespace_path / Path("_configuration.py"),
407
- general_serializer.serialize_config_file(clients),
372
+ exec_path / Path(f"{async_path}__init__.py"),
373
+ general_serializer.serialize_init_file([c for c in clients if c.has_operations]),
408
374
  )
409
375
 
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)
376
+ # if there was a patch file before, we keep it
377
+ self._keep_patch_file(exec_path / Path(f"{async_path}_patch.py"), env)
414
378
 
415
- self.write_file(
416
- namespace_path / Path("__init__.py"),
417
- general_serializer.serialize_init_file(clients),
418
- )
379
+ if self.code_model.clients_has_operations(clients):
419
380
 
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
- )
381
+ # write client file
382
+ self.write_file(
383
+ exec_path / Path(f"{async_path}{self.code_model.client_filename}.py"),
384
+ general_serializer.serialize_service_client_file(clients),
385
+ )
427
386
 
428
- self._serialize_and_write_version_file(namespace_path, general_serializer)
387
+ # write config file
388
+ self.write_file(
389
+ exec_path / Path(f"{async_path}_configuration.py"),
390
+ general_serializer.serialize_config_file(clients),
391
+ )
392
+
393
+ # sometimes we need define additional Mixin class for client in _vendor.py
394
+ self._serialize_and_write_vendor_file(env, namespace)
395
+
396
+ def _serialize_and_write_vendor_file(self, env: Environment, namespace: str) -> None:
397
+ exec_path = self.exec_path(namespace)
398
+ # write _vendor.py
399
+ for async_mode, async_path in self.serialize_loop:
400
+ if self.code_model.need_vendored_code(async_mode=async_mode, client_namespace=namespace):
401
+ self.write_file(
402
+ exec_path / Path(f"{async_path}_vendor.py"),
403
+ GeneralSerializer(
404
+ code_model=self.code_model, env=env, async_mode=async_mode, client_namespace=namespace
405
+ ).serialize_vendor_file(),
406
+ )
407
+
408
+ def _serialize_and_write_top_level_folder(self, env: Environment, namespace: str) -> None:
409
+ exec_path = self.exec_path(namespace)
410
+ # write _vendor.py
411
+ self._serialize_and_write_vendor_file(env, namespace)
412
+
413
+ general_serializer = GeneralSerializer(code_model=self.code_model, env=env, async_mode=False)
414
+
415
+ # write _version.py
416
+ self._serialize_and_write_version_file(namespace, general_serializer)
429
417
 
430
418
  # write the empty py.typed file
431
- self.write_file(namespace_path / Path("py.typed"), "# Marker file for PEP 561.")
419
+ self.write_file(exec_path / Path("py.typed"), "# Marker file for PEP 561.")
432
420
 
421
+ # write _serialization.py
433
422
  if not self.code_model.options["client_side_validation"] and not self.code_model.options["multiapi"]:
434
423
  self.write_file(
435
- namespace_path / Path("_serialization.py"),
424
+ exec_path / Path("_serialization.py"),
436
425
  general_serializer.serialize_serialization_file(),
437
426
  )
427
+
428
+ # write _model_base.py
438
429
  if self.code_model.options["models_mode"] == "dpg":
439
430
  self.write_file(
440
- namespace_path / Path("_model_base.py"),
431
+ exec_path / Path("_model_base.py"),
441
432
  general_serializer.serialize_model_base_file(),
442
433
  )
443
434
 
435
+ # write _validation.py
444
436
  if any(og for client in self.code_model.clients for og in client.operation_groups if og.need_validation):
445
437
  self.write_file(
446
- namespace_path / Path("_validation.py"),
438
+ exec_path / Path("_validation.py"),
447
439
  general_serializer.serialize_validation_file(),
448
440
  )
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
441
 
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):
442
+ # write _types.py
443
+ if self.code_model.named_unions:
477
444
  self.write_file(
478
- aio_path / Path("_vendor.py"),
479
- aio_general_serializer.serialize_vendor_file(clients),
445
+ exec_path / Path("_types.py"),
446
+ TypesSerializer(code_model=self.code_model, env=env).serialize(),
480
447
  )
481
448
 
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())
449
+ def _serialize_and_write_metadata(self, env: Environment, namespace: str) -> None:
450
+ metadata_serializer = MetadataSerializer(self.code_model, env, client_namespace=namespace)
451
+ self.write_file(self.exec_path(namespace) / Path("_metadata.json"), metadata_serializer.serialize())
485
452
 
486
453
  @property
487
454
  def _namespace_from_package_name(self) -> str:
@@ -493,9 +460,17 @@ class JinjaSerializer(ReaderAndWriter):
493
460
 
494
461
  return self._namespace_from_package_name
495
462
 
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))
463
+ @property
464
+ def exec_path_compensation(self) -> Path:
465
+ """Assume the process is running in the root folder of the package. If not, we need the path compensation."""
466
+ return (
467
+ Path("../" * (self._name_space().count(".") + 1))
468
+ if self.code_model.options["no_namespace_folders"]
469
+ else Path(".")
470
+ )
471
+
472
+ def exec_path(self, namespace: str) -> Path:
473
+ return self.exec_path_compensation / Path(*namespace.split("."))
499
474
 
500
475
  @property
501
476
  def _additional_folder(self) -> Path:
@@ -506,8 +481,8 @@ class JinjaSerializer(ReaderAndWriter):
506
481
  return Path("/".join(namespace_config.split(".")[num_of_package_namespace:]))
507
482
  return Path("")
508
483
 
509
- def _serialize_and_write_sample(self, env: Environment, namespace_path: Path):
510
- out_path = self._package_root_folder(namespace_path) / Path("generated_samples")
484
+ def _serialize_and_write_sample(self, env: Environment, namespace: str):
485
+ out_path = self.exec_path(namespace) / Path("generated_samples")
511
486
  for client in self.code_model.clients:
512
487
  for op_group in client.operation_groups:
513
488
  for operation in op_group.operations:
@@ -539,15 +514,15 @@ class JinjaSerializer(ReaderAndWriter):
539
514
  log_error = f"error happens in sample {file}: {e}"
540
515
  _LOGGER.error(log_error)
541
516
 
542
- def _serialize_and_write_test(self, env: Environment, namespace_path: Path):
517
+ def _serialize_and_write_test(self, env: Environment, namespace: str):
543
518
  self.code_model.for_test = True
544
- out_path = self._package_root_folder(namespace_path) / Path("generated_tests")
519
+ out_path = self.exec_path(namespace) / Path("generated_tests")
545
520
  general_serializer = TestGeneralSerializer(code_model=self.code_model, env=env)
546
521
  self.write_file(out_path / "conftest.py", general_serializer.serialize_conftest())
547
522
  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
523
+ for async_mode in (True, False):
524
+ async_suffix = "_async" if async_mode else ""
525
+ general_serializer.async_mode = async_mode
551
526
  self.write_file(
552
527
  out_path / f"testpreparer{async_suffix}.py",
553
528
  general_serializer.serialize_testpreparer(),
@@ -560,9 +535,9 @@ class JinjaSerializer(ReaderAndWriter):
560
535
  ):
561
536
  continue
562
537
  test_serializer = TestSerializer(self.code_model, env, client=client, operation_group=og)
563
- for is_async in (True, False):
538
+ for async_mode in (True, False):
564
539
  try:
565
- test_serializer.is_async = is_async
540
+ test_serializer.async_mode = async_mode
566
541
  self.write_file(
567
542
  out_path / f"{to_snake_case(test_serializer.test_class_name)}.py",
568
543
  test_serializer.serialize_test(),