@autorest/python 6.27.4 → 6.28.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) 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 +204 -33
  8. package/generator/build/lib/pygen/codegen/models/combined_type.py +12 -8
  9. package/generator/build/lib/pygen/codegen/models/constant_type.py +2 -3
  10. package/generator/build/lib/pygen/codegen/models/credential_types.py +6 -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 +74 -31
  19. package/generator/build/lib/pygen/codegen/models/operation_group.py +82 -12
  20. package/generator/build/lib/pygen/codegen/models/paging_operation.py +10 -7
  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 +9 -9
  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 +228 -243
  29. package/generator/build/lib/pygen/codegen/serializers/base_serializer.py +19 -1
  30. package/generator/build/lib/pygen/codegen/serializers/builder_serializer.py +58 -36
  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 +65 -24
  37. package/generator/build/lib/pygen/codegen/serializers/operation_groups_serializer.py +20 -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/operation_group.py.jinja2 +4 -4
  51. package/generator/build/lib/pygen/codegen/templates/operation_groups_container.py.jinja2 +2 -0
  52. package/generator/build/lib/pygen/codegen/templates/operations_folder_init.py.jinja2 +2 -4
  53. package/generator/build/lib/pygen/codegen/templates/serialization.py.jinja2 +2 -68
  54. package/generator/build/lib/pygen/codegen/templates/test.py.jinja2 +3 -3
  55. package/generator/build/lib/pygen/codegen/templates/testpreparer.py.jinja2 +2 -2
  56. package/generator/build/lib/pygen/codegen/templates/vendor.py.jinja2 +4 -4
  57. package/generator/build/lib/pygen/preprocess/__init__.py +0 -4
  58. package/generator/component-detection-pip-report.json +2 -2
  59. package/generator/dev_requirements.txt +2 -2
  60. package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
  61. package/generator/pygen/black.py +3 -3
  62. package/generator/pygen/codegen/__init__.py +2 -0
  63. package/generator/pygen/codegen/_utils.py +4 -0
  64. package/generator/pygen/codegen/models/base.py +2 -3
  65. package/generator/pygen/codegen/models/base_builder.py +5 -3
  66. package/generator/pygen/codegen/models/client.py +28 -19
  67. package/generator/pygen/codegen/models/code_model.py +204 -33
  68. package/generator/pygen/codegen/models/combined_type.py +12 -8
  69. package/generator/pygen/codegen/models/constant_type.py +2 -3
  70. package/generator/pygen/codegen/models/credential_types.py +6 -3
  71. package/generator/pygen/codegen/models/dictionary_type.py +2 -3
  72. package/generator/pygen/codegen/models/enum_type.py +47 -24
  73. package/generator/pygen/codegen/models/imports.py +14 -12
  74. package/generator/pygen/codegen/models/list_type.py +2 -3
  75. package/generator/pygen/codegen/models/lro_operation.py +8 -4
  76. package/generator/pygen/codegen/models/lro_paging_operation.py +2 -2
  77. package/generator/pygen/codegen/models/model_type.py +34 -19
  78. package/generator/pygen/codegen/models/operation.py +74 -31
  79. package/generator/pygen/codegen/models/operation_group.py +82 -12
  80. package/generator/pygen/codegen/models/paging_operation.py +10 -7
  81. package/generator/pygen/codegen/models/parameter.py +10 -10
  82. package/generator/pygen/codegen/models/parameter_list.py +7 -7
  83. package/generator/pygen/codegen/models/primitive_types.py +23 -43
  84. package/generator/pygen/codegen/models/property.py +9 -9
  85. package/generator/pygen/codegen/models/request_builder.py +9 -15
  86. package/generator/pygen/codegen/models/response.py +6 -8
  87. package/generator/pygen/codegen/models/utils.py +11 -0
  88. package/generator/pygen/codegen/serializers/__init__.py +228 -243
  89. package/generator/pygen/codegen/serializers/base_serializer.py +19 -1
  90. package/generator/pygen/codegen/serializers/builder_serializer.py +58 -36
  91. package/generator/pygen/codegen/serializers/client_serializer.py +9 -5
  92. package/generator/pygen/codegen/serializers/enum_serializer.py +17 -3
  93. package/generator/pygen/codegen/serializers/general_serializer.py +26 -14
  94. package/generator/pygen/codegen/serializers/metadata_serializer.py +26 -8
  95. package/generator/pygen/codegen/serializers/model_init_serializer.py +9 -4
  96. package/generator/pygen/codegen/serializers/model_serializer.py +65 -24
  97. package/generator/pygen/codegen/serializers/operation_groups_serializer.py +20 -16
  98. package/generator/pygen/codegen/serializers/operations_init_serializer.py +5 -10
  99. package/generator/pygen/codegen/serializers/parameter_serializer.py +10 -7
  100. package/generator/pygen/codegen/serializers/request_builders_serializer.py +10 -1
  101. package/generator/pygen/codegen/serializers/sample_serializer.py +7 -10
  102. package/generator/pygen/codegen/serializers/test_serializer.py +24 -28
  103. package/generator/pygen/codegen/serializers/types_serializer.py +6 -1
  104. package/generator/pygen/codegen/serializers/utils.py +1 -15
  105. package/generator/pygen/codegen/templates/client_container.py.jinja2 +1 -1
  106. package/generator/pygen/codegen/templates/config_container.py.jinja2 +1 -1
  107. package/generator/pygen/codegen/templates/enum_container.py.jinja2 +1 -1
  108. package/generator/pygen/codegen/templates/init.py.jinja2 +1 -1
  109. package/generator/pygen/codegen/templates/model_container.py.jinja2 +1 -1
  110. package/generator/pygen/codegen/templates/operation_group.py.jinja2 +4 -4
  111. package/generator/pygen/codegen/templates/operation_groups_container.py.jinja2 +2 -0
  112. package/generator/pygen/codegen/templates/operations_folder_init.py.jinja2 +2 -4
  113. package/generator/pygen/codegen/templates/serialization.py.jinja2 +2 -68
  114. package/generator/pygen/codegen/templates/test.py.jinja2 +3 -3
  115. package/generator/pygen/codegen/templates/testpreparer.py.jinja2 +2 -2
  116. package/generator/pygen/codegen/templates/vendor.py.jinja2 +4 -4
  117. package/generator/pygen/preprocess/__init__.py +0 -4
  118. package/generator/pygen.egg-info/PKG-INFO +10 -1
  119. package/package.json +2 -2
  120. 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,81 @@ 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
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
151
+ self.write_file(
152
+ exec_path / Path("__init__.py"),
153
+ general_serializer.serialize_pkgutil_init_file(),
154
+ )
160
155
 
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")):
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 (
163
+ self.code_model.has_non_json_models(client_namespace_type.models) or client_namespace_type.enums
164
+ ) and self.code_model.options["models_mode"]:
165
+ self._serialize_and_write_models_folder(
166
+ env=env,
167
+ namespace=client_namespace,
168
+ models=client_namespace_type.models,
169
+ enums=client_namespace_type.enums,
170
+ )
171
+
172
+ if not self.code_model.options["models_mode"]:
173
+ # keep models file if users ended up just writing a models file
174
+ model_path = exec_path / Path("models.py")
175
+ if self.read_file(model_path):
176
+ self.write_file(model_path, self.read_file(model_path))
177
+
178
+ # add operations folder if there are operations in this namespace
179
+ if client_namespace_type.operation_groups:
180
+ self._serialize_and_write_operations_folder(
181
+ client_namespace_type.operation_groups, env=env, namespace=client_namespace
182
+ )
183
+ if self.code_model.options["multiapi"]:
184
+ self._serialize_and_write_metadata(env=env, namespace=client_namespace)
185
+
186
+ # if there are only operations under this namespace, we need to add general __init__.py into `aio` folder
187
+ # to make sure all generated files could be packed into .zip/.whl/.tgz package
188
+ if not client_namespace_type.clients and client_namespace_type.operation_groups and self.has_aio_folder:
183
189
  self.write_file(
184
- namespace_path / Path("models.py"),
185
- self.read_file(namespace_path / Path("models.py")),
190
+ exec_path / Path("aio/__init__.py"),
191
+ general_serializer.serialize_pkgutil_init_file(),
186
192
  )
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
 
193
- def _serialize_and_write_package_files(self, namespace_path: Path) -> None:
194
- root_of_sdk = self._package_root_folder(namespace_path)
194
+ def _serialize_and_write_package_files(self, client_namespace: str) -> None:
195
+ root_of_sdk = self.exec_path(client_namespace)
195
196
  if self.code_model.options["package_mode"] in VALID_PACKAGE_MODE:
196
197
  env = Environment(
197
198
  loader=PackageLoader("pygen.codegen", "templates/packaging_templates"),
@@ -216,6 +217,9 @@ class JinjaSerializer(ReaderAndWriter):
216
217
  file = template_name.replace(".jinja2", "")
217
218
  output_name = root_of_sdk / file
218
219
  if not self.read_file(output_name) or file in _REGENERATE_FILES:
220
+ if self.keep_version_file and file == "setup.py":
221
+ # don't regenerate setup.py file if the version file is more up to date
222
+ continue
219
223
  self.write_file(
220
224
  output_name,
221
225
  serializer.serialize_package_file(template_name, **params),
@@ -230,25 +234,31 @@ class JinjaSerializer(ReaderAndWriter):
230
234
  PatchSerializer(env=env, code_model=self.code_model).serialize(),
231
235
  )
232
236
 
233
- def _serialize_and_write_models_folder(self, env: Environment, namespace_path: Path) -> None:
237
+ def _serialize_and_write_models_folder(
238
+ self, env: Environment, namespace: str, models: List[ModelType], enums: List[EnumType]
239
+ ) -> None:
234
240
  # Write the models folder
235
- models_path = namespace_path / Path("models")
241
+ models_path = self.exec_path(namespace + ".models")
236
242
  serializer = DpgModelSerializer if self.code_model.options["models_mode"] == "dpg" else MsrestModelSerializer
237
- if self.code_model.model_types:
243
+ if self.code_model.has_non_json_models(models):
238
244
  self.write_file(
239
245
  models_path / Path(f"{self.code_model.models_filename}.py"),
240
- serializer(code_model=self.code_model, env=env).serialize(),
246
+ serializer(code_model=self.code_model, env=env, client_namespace=namespace, models=models).serialize(),
241
247
  )
242
- if self.code_model.enums:
248
+ if enums:
243
249
  self.write_file(
244
250
  models_path / Path(f"{self.code_model.enums_filename}.py"),
245
- EnumSerializer(code_model=self.code_model, env=env).serialize(),
251
+ EnumSerializer(
252
+ code_model=self.code_model, env=env, client_namespace=namespace, enums=enums
253
+ ).serialize(),
246
254
  )
247
255
  self.write_file(
248
256
  models_path / Path("__init__.py"),
249
- ModelInitSerializer(code_model=self.code_model, env=env).serialize(),
257
+ ModelInitSerializer(code_model=self.code_model, env=env, models=models, enums=enums).serialize(),
250
258
  )
251
259
 
260
+ self._keep_patch_file(models_path / Path("_patch.py"), env)
261
+
252
262
  def _serialize_and_write_rest_layer(self, env: Environment, namespace_path: Path) -> None:
253
263
  rest_path = namespace_path / Path(self.code_model.rest_layer_name)
254
264
  group_names = {rb.group_name for c in self.code_model.clients for rb in c.request_builders}
@@ -292,196 +302,163 @@ class JinjaSerializer(ReaderAndWriter):
292
302
  ).serialize_init(),
293
303
  )
294
304
 
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
305
  def _serialize_and_write_operations_folder(
331
- self, clients: List[Client], env: Environment, namespace_path: Path
306
+ self, operation_groups: List[OperationGroup], env: Environment, namespace: str
332
307
  ) -> 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
308
+ operations_folder_name = self.code_model.operations_folder_name(namespace)
309
+ exec_path = self.exec_path(namespace)
310
+ for async_mode, async_path in self.serialize_loop:
311
+ prefix_path = f"{async_path}{operations_folder_name}"
312
+ # write init file
313
+ operations_init_serializer = OperationsInitSerializer(
314
+ code_model=self.code_model, operation_groups=operation_groups, env=env, async_mode=async_mode
346
315
  )
347
316
  self.write_file(
348
- namespace_path / Path("aio") / Path(self.code_model.operations_folder_name) / Path("__init__.py"),
349
- operations_async_init_serializer.serialize(),
317
+ exec_path / Path(f"{prefix_path}/__init__.py"),
318
+ operations_init_serializer.serialize(),
350
319
  )
351
320
 
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(
321
+ # write operations file
322
+ OgLoop = namedtuple("OgLoop", ["operation_groups", "filename"])
323
+ if self.code_model.options["combine_operation_files"]:
324
+ loops = [OgLoop(operation_groups, "_operations")]
325
+ else:
326
+ loops = [OgLoop([og], og.filename) for og in operation_groups]
327
+ for ogs, filename in loops:
328
+ operation_group_serializer = OperationGroupsSerializer(
329
+ code_model=self.code_model,
330
+ operation_groups=ogs,
361
331
  env=env,
362
- namespace_path=namespace_path,
363
- operation_group=operation_group,
364
- clients=clients,
332
+ async_mode=async_mode,
333
+ client_namespace=namespace,
334
+ )
335
+ self.write_file(
336
+ exec_path / Path(f"{prefix_path}/{filename}.py"),
337
+ operation_group_serializer.serialize(),
365
338
  )
366
339
 
340
+ # if there was a patch file before, we keep it
341
+ self._keep_patch_file(exec_path / Path(f"{prefix_path}/_patch.py"), env)
342
+
367
343
  def _serialize_and_write_version_file(
368
344
  self,
369
- namespace_path: Path,
345
+ namespace: str,
370
346
  general_serializer: GeneralSerializer,
371
347
  ):
348
+ exec_path = self.exec_path(namespace)
349
+
372
350
  def _read_version_file(original_version_file_name: str) -> str:
373
- return self.read_file(namespace_path / original_version_file_name)
351
+ return self.read_file(exec_path / original_version_file_name)
374
352
 
375
353
  def _write_version_file(original_version_file_name: str) -> None:
376
354
  self.write_file(
377
- namespace_path / Path("_version.py"),
355
+ exec_path / Path("_version.py"),
378
356
  _read_version_file(original_version_file_name),
379
357
  )
380
358
 
381
- keep_version_file = self.code_model.options["keep_version_file"]
382
- if keep_version_file and _read_version_file("_version.py"):
359
+ if self.keep_version_file and _read_version_file("_version.py"):
383
360
  _write_version_file(original_version_file_name="_version.py")
384
- elif keep_version_file and _read_version_file("version.py"):
361
+ elif self.keep_version_file and _read_version_file("version.py"):
385
362
  _write_version_file(original_version_file_name="version.py")
386
363
  elif self.code_model.options["package_version"]:
387
364
  self.write_file(
388
- namespace_path / Path("_version.py"),
365
+ exec_path / Path("_version.py"),
389
366
  general_serializer.serialize_version_file(),
390
367
  )
391
368
 
392
369
  def _serialize_client_and_config_files(
393
370
  self,
394
- namespace_path: Path,
395
- general_serializer: GeneralSerializer,
396
- async_mode: bool,
371
+ namespace: str,
397
372
  clients: List[Client],
373
+ env: Environment,
398
374
  ) -> 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),
375
+ exec_path = self.exec_path(namespace)
376
+ for async_mode, async_path in self.serialize_loop:
377
+ general_serializer = GeneralSerializer(
378
+ code_model=self.code_model, env=env, async_mode=async_mode, client_namespace=namespace
404
379
  )
380
+ # when there is client.py, there must be __init__.py
405
381
  self.write_file(
406
- namespace_path / Path("_configuration.py"),
407
- general_serializer.serialize_config_file(clients),
382
+ exec_path / Path(f"{async_path}__init__.py"),
383
+ general_serializer.serialize_init_file([c for c in clients if c.has_operations]),
408
384
  )
409
385
 
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)
386
+ # if there was a patch file before, we keep it
387
+ self._keep_patch_file(exec_path / Path(f"{async_path}_patch.py"), env)
414
388
 
415
- self.write_file(
416
- namespace_path / Path("__init__.py"),
417
- general_serializer.serialize_init_file(clients),
418
- )
389
+ if self.code_model.clients_has_operations(clients):
419
390
 
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
- )
391
+ # write client file
392
+ self.write_file(
393
+ exec_path / Path(f"{async_path}{self.code_model.client_filename}.py"),
394
+ general_serializer.serialize_service_client_file(clients),
395
+ )
427
396
 
428
- self._serialize_and_write_version_file(namespace_path, general_serializer)
397
+ # write config file
398
+ self.write_file(
399
+ exec_path / Path(f"{async_path}_configuration.py"),
400
+ general_serializer.serialize_config_file(clients),
401
+ )
402
+
403
+ # sometimes we need define additional Mixin class for client in _vendor.py
404
+ self._serialize_and_write_vendor_file(env, namespace)
405
+
406
+ def _serialize_and_write_vendor_file(self, env: Environment, namespace: str) -> None:
407
+ exec_path = self.exec_path(namespace)
408
+ # write _vendor.py
409
+ for async_mode, async_path in self.serialize_loop:
410
+ if self.code_model.need_vendored_code(async_mode=async_mode, client_namespace=namespace):
411
+ self.write_file(
412
+ exec_path / Path(f"{async_path}_vendor.py"),
413
+ GeneralSerializer(
414
+ code_model=self.code_model, env=env, async_mode=async_mode, client_namespace=namespace
415
+ ).serialize_vendor_file(),
416
+ )
417
+
418
+ def _serialize_and_write_top_level_folder(self, env: Environment, namespace: str) -> None:
419
+ exec_path = self.exec_path(namespace)
420
+ # write _vendor.py
421
+ self._serialize_and_write_vendor_file(env, namespace)
422
+
423
+ general_serializer = GeneralSerializer(code_model=self.code_model, env=env, async_mode=False)
424
+
425
+ # write _version.py
426
+ self._serialize_and_write_version_file(namespace, general_serializer)
429
427
 
430
428
  # write the empty py.typed file
431
- self.write_file(namespace_path / Path("py.typed"), "# Marker file for PEP 561.")
429
+ self.write_file(exec_path / Path("py.typed"), "# Marker file for PEP 561.")
432
430
 
431
+ # write _serialization.py
433
432
  if not self.code_model.options["client_side_validation"] and not self.code_model.options["multiapi"]:
434
433
  self.write_file(
435
- namespace_path / Path("_serialization.py"),
434
+ exec_path / Path("_serialization.py"),
436
435
  general_serializer.serialize_serialization_file(),
437
436
  )
437
+
438
+ # write _model_base.py
438
439
  if self.code_model.options["models_mode"] == "dpg":
439
440
  self.write_file(
440
- namespace_path / Path("_model_base.py"),
441
+ exec_path / Path("_model_base.py"),
441
442
  general_serializer.serialize_model_base_file(),
442
443
  )
443
444
 
445
+ # write _validation.py
444
446
  if any(og for client in self.code_model.clients for og in client.operation_groups if og.need_validation):
445
447
  self.write_file(
446
- namespace_path / Path("_validation.py"),
448
+ exec_path / Path("_validation.py"),
447
449
  general_serializer.serialize_validation_file(),
448
450
  )
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
451
 
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):
452
+ # write _types.py
453
+ if self.code_model.named_unions:
477
454
  self.write_file(
478
- aio_path / Path("_vendor.py"),
479
- aio_general_serializer.serialize_vendor_file(clients),
455
+ exec_path / Path("_types.py"),
456
+ TypesSerializer(code_model=self.code_model, env=env).serialize(),
480
457
  )
481
458
 
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())
459
+ def _serialize_and_write_metadata(self, env: Environment, namespace: str) -> None:
460
+ metadata_serializer = MetadataSerializer(self.code_model, env, client_namespace=namespace)
461
+ self.write_file(self.exec_path(namespace) / Path("_metadata.json"), metadata_serializer.serialize())
485
462
 
486
463
  @property
487
464
  def _namespace_from_package_name(self) -> str:
@@ -493,9 +470,17 @@ class JinjaSerializer(ReaderAndWriter):
493
470
 
494
471
  return self._namespace_from_package_name
495
472
 
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))
473
+ @property
474
+ def exec_path_compensation(self) -> Path:
475
+ """Assume the process is running in the root folder of the package. If not, we need the path compensation."""
476
+ return (
477
+ Path("../" * (self._name_space().count(".") + 1))
478
+ if self.code_model.options["no_namespace_folders"]
479
+ else Path(".")
480
+ )
481
+
482
+ def exec_path(self, namespace: str) -> Path:
483
+ return self.exec_path_compensation / Path(*namespace.split("."))
499
484
 
500
485
  @property
501
486
  def _additional_folder(self) -> Path:
@@ -506,8 +491,8 @@ class JinjaSerializer(ReaderAndWriter):
506
491
  return Path("/".join(namespace_config.split(".")[num_of_package_namespace:]))
507
492
  return Path("")
508
493
 
509
- def _serialize_and_write_sample(self, env: Environment, namespace_path: Path):
510
- out_path = self._package_root_folder(namespace_path) / Path("generated_samples")
494
+ def _serialize_and_write_sample(self, env: Environment, namespace: str):
495
+ out_path = self.exec_path(namespace) / Path("generated_samples")
511
496
  for client in self.code_model.clients:
512
497
  for op_group in client.operation_groups:
513
498
  for operation in op_group.operations:
@@ -539,15 +524,15 @@ class JinjaSerializer(ReaderAndWriter):
539
524
  log_error = f"error happens in sample {file}: {e}"
540
525
  _LOGGER.error(log_error)
541
526
 
542
- def _serialize_and_write_test(self, env: Environment, namespace_path: Path):
527
+ def _serialize_and_write_test(self, env: Environment, namespace: str):
543
528
  self.code_model.for_test = True
544
- out_path = self._package_root_folder(namespace_path) / Path("generated_tests")
529
+ out_path = self.exec_path(namespace) / Path("generated_tests")
545
530
  general_serializer = TestGeneralSerializer(code_model=self.code_model, env=env)
546
531
  self.write_file(out_path / "conftest.py", general_serializer.serialize_conftest())
547
532
  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
533
+ for async_mode in (True, False):
534
+ async_suffix = "_async" if async_mode else ""
535
+ general_serializer.async_mode = async_mode
551
536
  self.write_file(
552
537
  out_path / f"testpreparer{async_suffix}.py",
553
538
  general_serializer.serialize_testpreparer(),
@@ -560,9 +545,9 @@ class JinjaSerializer(ReaderAndWriter):
560
545
  ):
561
546
  continue
562
547
  test_serializer = TestSerializer(self.code_model, env, client=client, operation_group=og)
563
- for is_async in (True, False):
548
+ for async_mode in (True, False):
564
549
  try:
565
- test_serializer.is_async = is_async
550
+ test_serializer.async_mode = async_mode
566
551
  self.write_file(
567
552
  out_path / f"{to_snake_case(test_serializer.test_class_name)}.py",
568
553
  test_serializer.serialize_test(),