@azure-tools/typespec-python 0.24.3 → 0.25.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 (132) hide show
  1. package/dist/src/code-model.d.ts.map +1 -1
  2. package/dist/src/code-model.js +1 -4
  3. package/dist/src/code-model.js.map +1 -1
  4. package/dist/src/emitter.d.ts.map +1 -1
  5. package/dist/src/emitter.js +5 -4
  6. package/dist/src/emitter.js.map +1 -1
  7. package/dist/src/external-process.d.ts +0 -9
  8. package/dist/src/external-process.d.ts.map +1 -1
  9. package/dist/src/external-process.js +1 -25
  10. package/dist/src/external-process.js.map +1 -1
  11. package/dist/src/types.d.ts.map +1 -1
  12. package/dist/src/types.js +2 -0
  13. package/dist/src/types.js.map +1 -1
  14. package/generator/LICENSE +21 -0
  15. package/generator/README.md +1 -0
  16. package/generator/dev_requirements.txt +5 -0
  17. package/generator/pygen/__init__.py +107 -0
  18. package/generator/pygen/_version.py +7 -0
  19. package/generator/pygen/black.py +71 -0
  20. package/generator/pygen/codegen/__init__.py +334 -0
  21. package/generator/pygen/codegen/_utils.py +16 -0
  22. package/generator/pygen/codegen/models/__init__.py +202 -0
  23. package/generator/pygen/codegen/models/base.py +186 -0
  24. package/generator/pygen/codegen/models/base_builder.py +119 -0
  25. package/generator/pygen/codegen/models/client.py +429 -0
  26. package/generator/pygen/codegen/models/code_model.py +239 -0
  27. package/generator/pygen/codegen/models/combined_type.py +149 -0
  28. package/generator/pygen/codegen/models/constant_type.py +129 -0
  29. package/generator/pygen/codegen/models/credential_types.py +221 -0
  30. package/generator/pygen/codegen/models/dictionary_type.py +127 -0
  31. package/generator/pygen/codegen/models/enum_type.py +238 -0
  32. package/generator/pygen/codegen/models/imports.py +291 -0
  33. package/generator/pygen/codegen/models/list_type.py +143 -0
  34. package/generator/pygen/codegen/models/lro_operation.py +143 -0
  35. package/generator/pygen/codegen/models/lro_paging_operation.py +32 -0
  36. package/generator/pygen/codegen/models/model_type.py +361 -0
  37. package/generator/pygen/codegen/models/operation.py +518 -0
  38. package/generator/pygen/codegen/models/operation_group.py +184 -0
  39. package/generator/pygen/codegen/models/paging_operation.py +156 -0
  40. package/generator/pygen/codegen/models/parameter.py +402 -0
  41. package/generator/pygen/codegen/models/parameter_list.py +390 -0
  42. package/generator/pygen/codegen/models/primitive_types.py +626 -0
  43. package/generator/pygen/codegen/models/property.py +175 -0
  44. package/generator/pygen/codegen/models/request_builder.py +189 -0
  45. package/generator/pygen/codegen/models/request_builder_parameter.py +115 -0
  46. package/generator/pygen/codegen/models/response.py +348 -0
  47. package/generator/pygen/codegen/models/utils.py +23 -0
  48. package/generator/pygen/codegen/serializers/__init__.py +570 -0
  49. package/generator/pygen/codegen/serializers/base_serializer.py +21 -0
  50. package/generator/pygen/codegen/serializers/builder_serializer.py +1454 -0
  51. package/generator/pygen/codegen/serializers/client_serializer.py +295 -0
  52. package/generator/pygen/codegen/serializers/enum_serializer.py +15 -0
  53. package/generator/pygen/codegen/serializers/general_serializer.py +212 -0
  54. package/generator/pygen/codegen/serializers/import_serializer.py +127 -0
  55. package/generator/pygen/codegen/serializers/metadata_serializer.py +198 -0
  56. package/generator/pygen/codegen/serializers/model_init_serializer.py +33 -0
  57. package/generator/pygen/codegen/serializers/model_serializer.py +287 -0
  58. package/generator/pygen/codegen/serializers/operation_groups_serializer.py +89 -0
  59. package/generator/pygen/codegen/serializers/operations_init_serializer.py +44 -0
  60. package/generator/pygen/codegen/serializers/parameter_serializer.py +221 -0
  61. package/generator/pygen/codegen/serializers/patch_serializer.py +19 -0
  62. package/generator/pygen/codegen/serializers/request_builders_serializer.py +52 -0
  63. package/generator/pygen/codegen/serializers/sample_serializer.py +163 -0
  64. package/generator/pygen/codegen/serializers/test_serializer.py +287 -0
  65. package/generator/pygen/codegen/serializers/types_serializer.py +31 -0
  66. package/generator/pygen/codegen/serializers/utils.py +68 -0
  67. package/generator/pygen/codegen/templates/client.py.jinja2 +37 -0
  68. package/generator/pygen/codegen/templates/client_container.py.jinja2 +12 -0
  69. package/generator/pygen/codegen/templates/config.py.jinja2 +73 -0
  70. package/generator/pygen/codegen/templates/config_container.py.jinja2 +16 -0
  71. package/generator/pygen/codegen/templates/conftest.py.jinja2 +28 -0
  72. package/generator/pygen/codegen/templates/enum.py.jinja2 +13 -0
  73. package/generator/pygen/codegen/templates/enum_container.py.jinja2 +10 -0
  74. package/generator/pygen/codegen/templates/init.py.jinja2 +24 -0
  75. package/generator/pygen/codegen/templates/keywords.jinja2 +19 -0
  76. package/generator/pygen/codegen/templates/lro_operation.py.jinja2 +16 -0
  77. package/generator/pygen/codegen/templates/lro_paging_operation.py.jinja2 +18 -0
  78. package/generator/pygen/codegen/templates/macros.jinja2 +12 -0
  79. package/generator/pygen/codegen/templates/metadata.json.jinja2 +167 -0
  80. package/generator/pygen/codegen/templates/model_base.py.jinja2 +899 -0
  81. package/generator/pygen/codegen/templates/model_container.py.jinja2 +13 -0
  82. package/generator/pygen/codegen/templates/model_dpg.py.jinja2 +92 -0
  83. package/generator/pygen/codegen/templates/model_init.py.jinja2 +28 -0
  84. package/generator/pygen/codegen/templates/model_msrest.py.jinja2 +92 -0
  85. package/generator/pygen/codegen/templates/operation.py.jinja2 +21 -0
  86. package/generator/pygen/codegen/templates/operation_group.py.jinja2 +75 -0
  87. package/generator/pygen/codegen/templates/operation_groups_container.py.jinja2 +20 -0
  88. package/generator/pygen/codegen/templates/operation_tools.jinja2 +74 -0
  89. package/generator/pygen/codegen/templates/operations_folder_init.py.jinja2 +17 -0
  90. package/generator/pygen/codegen/templates/packaging_templates/CHANGELOG.md.jinja2 +6 -0
  91. package/generator/pygen/codegen/templates/packaging_templates/LICENSE.jinja2 +21 -0
  92. package/generator/pygen/codegen/templates/packaging_templates/MANIFEST.in.jinja2 +8 -0
  93. package/generator/pygen/codegen/templates/packaging_templates/README.md.jinja2 +107 -0
  94. package/generator/pygen/codegen/templates/packaging_templates/dev_requirements.txt.jinja2 +9 -0
  95. package/generator/pygen/codegen/templates/packaging_templates/setup.py.jinja2 +108 -0
  96. package/generator/pygen/codegen/templates/paging_operation.py.jinja2 +21 -0
  97. package/generator/pygen/codegen/templates/patch.py.jinja2 +19 -0
  98. package/generator/pygen/codegen/templates/pkgutil_init.py.jinja2 +1 -0
  99. package/generator/pygen/codegen/templates/request_builder.py.jinja2 +28 -0
  100. package/generator/pygen/codegen/templates/request_builders.py.jinja2 +10 -0
  101. package/generator/pygen/codegen/templates/rest_init.py.jinja2 +12 -0
  102. package/generator/pygen/codegen/templates/sample.py.jinja2 +44 -0
  103. package/generator/pygen/codegen/templates/serialization.py.jinja2 +2006 -0
  104. package/generator/pygen/codegen/templates/test.py.jinja2 +50 -0
  105. package/generator/pygen/codegen/templates/testpreparer.py.jinja2 +26 -0
  106. package/generator/pygen/codegen/templates/types.py.jinja2 +8 -0
  107. package/generator/pygen/codegen/templates/validation.py.jinja2 +38 -0
  108. package/generator/pygen/codegen/templates/vendor.py.jinja2 +98 -0
  109. package/generator/pygen/codegen/templates/version.py.jinja2 +4 -0
  110. package/generator/pygen/m2r.py +65 -0
  111. package/generator/pygen/postprocess/__init__.py +183 -0
  112. package/generator/pygen/postprocess/get_all.py +19 -0
  113. package/generator/pygen/postprocess/venvtools.py +77 -0
  114. package/generator/pygen/preprocess/__init__.py +503 -0
  115. package/generator/pygen/preprocess/helpers.py +27 -0
  116. package/generator/pygen/preprocess/python_mappings.py +222 -0
  117. package/generator/pygen/utils.py +149 -0
  118. package/generator/pygen.egg-info/PKG-INFO +25 -0
  119. package/generator/pygen.egg-info/SOURCES.txt +66 -0
  120. package/generator/pygen.egg-info/dependency_links.txt +1 -0
  121. package/generator/pygen.egg-info/requires.txt +4 -0
  122. package/generator/pygen.egg-info/top_level.txt +1 -0
  123. package/generator/requirements.txt +12 -0
  124. package/generator/setup.py +55 -0
  125. package/package.json +10 -7
  126. package/scripts/__pycache__/venvtools.cpython-38.pyc +0 -0
  127. package/scripts/install.py +49 -0
  128. package/scripts/prepare.py +38 -0
  129. package/scripts/run-python3.cjs +22 -0
  130. package/scripts/run_tsp.py +40 -0
  131. package/scripts/system-requirements.cjs +180 -0
  132. package/scripts/venvtools.py +81 -0
@@ -0,0 +1,429 @@
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 typing import Any, Dict, TYPE_CHECKING, TypeVar, Generic, Union, List, Optional
7
+
8
+ from .base import BaseModel
9
+ from .parameter_list import ClientGlobalParameterList, ConfigGlobalParameterList
10
+ from .imports import FileImport, ImportType, TypingSection, MsrestImportType
11
+ from .utils import add_to_pylint_disable, NAME_LENGTH_LIMIT
12
+ from .operation_group import OperationGroup
13
+ from .request_builder import (
14
+ RequestBuilder,
15
+ OverloadedRequestBuilder,
16
+ get_request_builder,
17
+ )
18
+ from .parameter import Parameter, ParameterMethodLocation
19
+ from .lro_operation import LROOperation
20
+ from .lro_paging_operation import LROPagingOperation
21
+
22
+ ParameterListType = TypeVar(
23
+ "ParameterListType",
24
+ bound=Union[ClientGlobalParameterList, ConfigGlobalParameterList],
25
+ )
26
+
27
+ if TYPE_CHECKING:
28
+ from .code_model import CodeModel
29
+ from . import OperationType
30
+
31
+
32
+ class _ClientConfigBase(Generic[ParameterListType], BaseModel):
33
+ """The service client base. Shared across our Client and Config type"""
34
+
35
+ def __init__(
36
+ self,
37
+ yaml_data: Dict[str, Any],
38
+ code_model: "CodeModel",
39
+ parameters: ParameterListType,
40
+ ):
41
+ super().__init__(yaml_data, code_model)
42
+ self.parameters = parameters
43
+ self.url: str = self.yaml_data["url"] # the base endpoint of the client. Can be parameterized or not
44
+ self.legacy_filename: str = self.yaml_data.get("legacyFilename", "client")
45
+
46
+ @property
47
+ def description(self) -> str:
48
+ return self.yaml_data["description"]
49
+
50
+ @property
51
+ def name(self) -> str:
52
+ return self.yaml_data["name"]
53
+
54
+
55
+ class Client(_ClientConfigBase[ClientGlobalParameterList]):
56
+ """Model representing our service client"""
57
+
58
+ def __init__(
59
+ self,
60
+ yaml_data: Dict[str, Any],
61
+ code_model: "CodeModel",
62
+ parameters: ClientGlobalParameterList,
63
+ *,
64
+ is_subclient: bool = False,
65
+ ):
66
+ super().__init__(yaml_data, code_model, parameters)
67
+ self.operation_groups: List[OperationGroup] = []
68
+ self.config = Config.from_yaml(yaml_data, self.code_model)
69
+ self.is_subclient = is_subclient
70
+ self.request_builders = self._build_request_builders()
71
+ if self.code_model.options["show_operations"]:
72
+ self.operation_groups = [
73
+ OperationGroup.from_yaml(op_group, code_model, self)
74
+ for op_group in self.yaml_data.get("operationGroups", [])
75
+ ]
76
+ self.link_lro_initial_operations()
77
+ self.request_id_header_name = self.yaml_data.get("requestIdHeaderName", None)
78
+ self.has_etag: bool = yaml_data.get("hasEtag", False)
79
+
80
+ def _build_request_builders(
81
+ self,
82
+ ) -> List[Union[RequestBuilder, OverloadedRequestBuilder]]:
83
+ request_builders: List[Union[RequestBuilder, OverloadedRequestBuilder]] = []
84
+
85
+ def add_og_request_builder(og: Dict[str, Any]):
86
+ for operation_yaml in og["operations"]:
87
+ request_builder = get_request_builder(
88
+ operation_yaml,
89
+ code_model=self.code_model,
90
+ client=self,
91
+ )
92
+ if operation_yaml.get("isLroInitialOperation"):
93
+ # we want to change the name
94
+ request_builder.name = request_builder.get_name(
95
+ request_builder.yaml_data["name"][1 : -len("_initial")],
96
+ request_builder.yaml_data,
97
+ request_builder.code_model,
98
+ request_builder.client,
99
+ )
100
+ if request_builder.overloads:
101
+ request_builders.extend(request_builder.overloads)
102
+ request_builders.append(request_builder)
103
+ if operation_yaml.get("nextOperation"):
104
+ # i am a paging operation and i have a next operation.
105
+ # Make sure to include my next operation
106
+ request_builders.append(
107
+ get_request_builder(
108
+ operation_yaml["nextOperation"],
109
+ code_model=self.code_model,
110
+ client=self,
111
+ )
112
+ )
113
+
114
+ queue = self.yaml_data.get("operationGroups", []).copy()
115
+ while queue:
116
+ now = queue.pop(0)
117
+ add_og_request_builder(now)
118
+ if now.get("operationGroups"):
119
+ queue.extend(now["operationGroups"])
120
+
121
+ return request_builders
122
+
123
+ def pipeline_class(self, async_mode: bool) -> str:
124
+ if self.code_model.options["azure_arm"]:
125
+ if async_mode:
126
+ return "AsyncARMPipelineClient"
127
+ return "ARMPipelineClient"
128
+ if async_mode:
129
+ return "AsyncPipelineClient"
130
+ return "PipelineClient"
131
+
132
+ @property
133
+ def credential(self) -> Optional[Parameter]:
134
+ """The credential param, if one exists"""
135
+ return self.parameters.credential
136
+
137
+ @property
138
+ def send_request_name(self) -> str:
139
+ """Name of the send request function"""
140
+ return "send_request" if self.code_model.options["show_send_request"] else "_send_request"
141
+
142
+ @property
143
+ def has_parameterized_host(self) -> bool:
144
+ """Whether the base url is parameterized or not"""
145
+ return not any(p for p in self.parameters if p.is_host)
146
+
147
+ @property
148
+ def pylint_disable(self) -> str:
149
+ retval = add_to_pylint_disable("", "client-accepts-api-version-keyword")
150
+ if len(self.operation_groups) > 6:
151
+ retval = add_to_pylint_disable(retval, "too-many-instance-attributes")
152
+ if len(self.name) > NAME_LENGTH_LIMIT:
153
+ retval = add_to_pylint_disable(retval, "name-too-long")
154
+ return retval
155
+
156
+ @property
157
+ def url_pylint_disable(self) -> str:
158
+ # if the url is too long
159
+ retval = ""
160
+ if len(self.url) > 85:
161
+ retval = add_to_pylint_disable(retval, "line-too-long")
162
+ return retval
163
+
164
+ @property
165
+ def filename(self) -> str:
166
+ """Name of the file for the client"""
167
+ if self.code_model.options["version_tolerant"] or self.code_model.options["low_level_client"]:
168
+ return "_client"
169
+ return f"_{self.legacy_filename}"
170
+
171
+ def lookup_request_builder(self, request_builder_id: int) -> Union[RequestBuilder, OverloadedRequestBuilder]:
172
+ """Find the request builder based off of id"""
173
+ try:
174
+ return next(rb for rb in self.request_builders if id(rb.yaml_data) == request_builder_id)
175
+ except StopIteration as exc:
176
+ raise KeyError(f"No request builder with id {request_builder_id} found.") from exc
177
+
178
+ def lookup_operation(self, operation_id: int) -> "OperationType":
179
+ try:
180
+ return next(o for og in self.operation_groups for o in og.operations if id(o.yaml_data) == operation_id)
181
+ except StopIteration as exc:
182
+ raise KeyError(f"No operation with id {operation_id} found.") from exc
183
+
184
+ def _imports_shared(self, async_mode: bool) -> FileImport:
185
+ file_import = FileImport(self.code_model)
186
+ file_import.add_submodule_import("typing", "Any", ImportType.STDLIB, TypingSection.CONDITIONAL)
187
+ if self.code_model.options["azure_arm"]:
188
+ file_import.add_submodule_import("azure.mgmt.core", self.pipeline_class(async_mode), ImportType.SDKCORE)
189
+ else:
190
+ file_import.add_submodule_import(
191
+ "" if self.code_model.is_azure_flavor else "runtime",
192
+ self.pipeline_class(async_mode),
193
+ ImportType.SDKCORE,
194
+ )
195
+
196
+ for gp in self.parameters:
197
+ if gp.method_location == ParameterMethodLocation.KWARG:
198
+ continue
199
+ file_import.merge(
200
+ gp.imports(
201
+ async_mode,
202
+ relative_path=".." if async_mode else ".",
203
+ operation=True,
204
+ )
205
+ )
206
+ file_import.add_submodule_import(
207
+ "._configuration",
208
+ f"{self.name}Configuration",
209
+ ImportType.LOCAL,
210
+ )
211
+ file_import.add_msrest_import(
212
+ relative_path=".." if async_mode else ".",
213
+ msrest_import_type=MsrestImportType.SerializerDeserializer,
214
+ typing_section=TypingSection.REGULAR,
215
+ )
216
+ file_import.add_submodule_import(
217
+ "pipeline" if self.code_model.is_azure_flavor else "runtime",
218
+ "policies",
219
+ ImportType.SDKCORE,
220
+ )
221
+ if self.code_model.options["azure_arm"]:
222
+ async_prefix = "Async" if async_mode else ""
223
+ file_import.add_submodule_import(
224
+ "azure.mgmt.core.policies",
225
+ f"{async_prefix}ARMAutoResourceProviderRegistrationPolicy",
226
+ ImportType.SDKCORE,
227
+ )
228
+
229
+ # import for "Self"
230
+ file_import.add_submodule_import(
231
+ "typing_extensions",
232
+ "Self",
233
+ ImportType.STDLIB,
234
+ )
235
+ return file_import
236
+
237
+ @property
238
+ def has_mixin(self) -> bool:
239
+ """Do we want a mixin ABC class for typing purposes?"""
240
+ return any(og for og in self.operation_groups if og.is_mixin)
241
+
242
+ @property
243
+ def lro_operations(self) -> List["OperationType"]:
244
+ """all LRO operations in this SDK?"""
245
+ return [operation for operation_group in self.operation_groups for operation in operation_group.lro_operations]
246
+
247
+ @property
248
+ def has_public_lro_operations(self) -> bool:
249
+ """Are there any public LRO operations in this SDK?"""
250
+ return any(not operation.internal for operation in self.lro_operations)
251
+
252
+ @property
253
+ def has_operations(self) -> bool:
254
+ return any(operation_group.has_operations for operation_group in self.operation_groups)
255
+
256
+ def link_lro_initial_operations(self) -> None:
257
+ """Link each LRO operation to its initial operation"""
258
+ for operation_group in self.operation_groups:
259
+ for operation in operation_group.operations:
260
+ if isinstance(operation, (LROOperation, LROPagingOperation)):
261
+ operation.initial_operation = self.lookup_operation(id(operation.yaml_data["initialOperation"]))
262
+
263
+ @property
264
+ def has_abstract_operations(self) -> bool:
265
+ """Whether there is abstract operation in any operation group."""
266
+ return any(og.has_abstract_operations for og in self.operation_groups)
267
+
268
+ @property
269
+ def has_non_abstract_operations(self) -> bool:
270
+ """Whether there is non-abstract operation in any operation group."""
271
+ return any(og.has_non_abstract_operations for og in self.operation_groups)
272
+
273
+ def imports(self, async_mode: bool) -> FileImport:
274
+ file_import = self._imports_shared(async_mode)
275
+ if async_mode:
276
+ file_import.add_submodule_import("typing", "Awaitable", ImportType.STDLIB)
277
+ file_import.add_submodule_import(
278
+ "rest",
279
+ "AsyncHttpResponse",
280
+ ImportType.SDKCORE,
281
+ TypingSection.CONDITIONAL,
282
+ )
283
+ else:
284
+ file_import.add_submodule_import(
285
+ "rest",
286
+ "HttpResponse",
287
+ ImportType.SDKCORE,
288
+ TypingSection.CONDITIONAL,
289
+ )
290
+ file_import.add_submodule_import(
291
+ "rest",
292
+ "HttpRequest",
293
+ ImportType.SDKCORE,
294
+ TypingSection.CONDITIONAL,
295
+ )
296
+ for og in self.operation_groups:
297
+ file_import.add_submodule_import(
298
+ f".{self.code_model.operations_folder_name}",
299
+ og.class_name,
300
+ ImportType.LOCAL,
301
+ )
302
+
303
+ if self.code_model.model_types and self.code_model.options["models_mode"] == "msrest":
304
+ path_to_models = ".." if async_mode else "."
305
+ file_import.add_submodule_import(path_to_models, "models", ImportType.LOCAL, alias="_models")
306
+ elif self.code_model.options["models_mode"] == "msrest":
307
+ # in this case, we have client_models = {} in the service client, which needs a type annotation
308
+ # this import will always be commented, so will always add it to the typing section
309
+ file_import.add_submodule_import("typing", "Dict", ImportType.STDLIB)
310
+ file_import.add_submodule_import("copy", "deepcopy", ImportType.STDLIB)
311
+ return file_import
312
+
313
+ def imports_for_multiapi(self, async_mode: bool) -> FileImport:
314
+ file_import = self._imports_shared(async_mode)
315
+ file_import.add_submodule_import("typing", "Optional", ImportType.STDLIB, TypingSection.CONDITIONAL)
316
+ try:
317
+ mixin_operation = next(og for og in self.operation_groups if og.is_mixin)
318
+ file_import.add_submodule_import("._operations_mixin", mixin_operation.class_name, ImportType.LOCAL)
319
+ except StopIteration:
320
+ pass
321
+ file_import.add_submodule_import("azure.profiles", "KnownProfiles", import_type=ImportType.SDKCORE)
322
+ file_import.add_submodule_import("azure.profiles", "ProfileDefinition", import_type=ImportType.SDKCORE)
323
+ file_import.add_submodule_import(
324
+ "azure.profiles.multiapiclient",
325
+ "MultiApiClientMixin",
326
+ import_type=ImportType.SDKCORE,
327
+ )
328
+ return file_import
329
+
330
+ @classmethod
331
+ def from_yaml(
332
+ cls,
333
+ yaml_data: Dict[str, Any],
334
+ code_model: "CodeModel",
335
+ *,
336
+ is_subclient: bool = False,
337
+ ) -> "Client":
338
+ return cls(
339
+ yaml_data=yaml_data,
340
+ code_model=code_model,
341
+ parameters=ClientGlobalParameterList.from_yaml(yaml_data, code_model),
342
+ is_subclient=is_subclient,
343
+ )
344
+
345
+
346
+ class Config(_ClientConfigBase[ConfigGlobalParameterList]):
347
+ """Model representing our Config type."""
348
+
349
+ @property
350
+ def pylint_disable(self) -> str:
351
+ retval = add_to_pylint_disable("", "too-many-instance-attributes")
352
+ if len(self.name) + len("Configuration") > NAME_LENGTH_LIMIT:
353
+ retval = add_to_pylint_disable(retval, "name-too-long")
354
+ return retval
355
+
356
+ @property
357
+ def description(self) -> str:
358
+ return (
359
+ f"Configuration for {self.yaml_data['name']}.\n\n."
360
+ "Note that all parameters used to create this instance are saved as instance attributes."
361
+ )
362
+
363
+ @property
364
+ def sdk_moniker(self) -> str:
365
+ package_name = self.code_model.options["package_name"]
366
+ if package_name and package_name.startswith("azure-"):
367
+ package_name = package_name[len("azure-") :]
368
+ return package_name if package_name else self.yaml_data["name"].lower()
369
+
370
+ @property
371
+ def name(self) -> str:
372
+ return f"{super().name}Configuration"
373
+
374
+ def _imports_shared(self, async_mode: bool) -> FileImport:
375
+ file_import = FileImport(self.code_model)
376
+ file_import.add_submodule_import(
377
+ "pipeline" if self.code_model.is_azure_flavor else "runtime",
378
+ "policies",
379
+ ImportType.SDKCORE,
380
+ )
381
+ file_import.add_submodule_import("typing", "Any", ImportType.STDLIB, TypingSection.CONDITIONAL)
382
+ if self.code_model.options["package_version"]:
383
+ file_import.add_submodule_import(".._version" if async_mode else "._version", "VERSION", ImportType.LOCAL)
384
+ if self.code_model.options["azure_arm"]:
385
+ policy = "AsyncARMChallengeAuthenticationPolicy" if async_mode else "ARMChallengeAuthenticationPolicy"
386
+ file_import.add_submodule_import("azure.mgmt.core.policies", "ARMHttpLoggingPolicy", ImportType.SDKCORE)
387
+ file_import.add_submodule_import("azure.mgmt.core.policies", policy, ImportType.SDKCORE)
388
+
389
+ return file_import
390
+
391
+ def imports(self, async_mode: bool) -> FileImport:
392
+ file_import = self._imports_shared(async_mode)
393
+ for gp in self.parameters:
394
+ if gp.method_location == ParameterMethodLocation.KWARG and gp not in self.parameters.kwargs_to_pop:
395
+ continue
396
+ file_import.merge(
397
+ gp.imports(
398
+ async_mode=async_mode,
399
+ relative_path=".." if async_mode else ".",
400
+ operation=True,
401
+ )
402
+ )
403
+ return file_import
404
+
405
+ def imports_for_multiapi(self, async_mode: bool) -> FileImport:
406
+ file_import = self._imports_shared(async_mode)
407
+ for gp in self.parameters:
408
+ if (
409
+ gp.method_location == ParameterMethodLocation.KWARG
410
+ and gp not in self.parameters.kwargs_to_pop
411
+ and gp.client_name == "api_version"
412
+ ):
413
+ continue
414
+ file_import.merge(
415
+ gp.imports_for_multiapi(
416
+ async_mode=async_mode,
417
+ relative_path=".." if async_mode else ".",
418
+ operation=True,
419
+ )
420
+ )
421
+ return file_import
422
+
423
+ @classmethod
424
+ def from_yaml(cls, yaml_data: Dict[str, Any], code_model: "CodeModel") -> "Config":
425
+ return cls(
426
+ yaml_data=yaml_data,
427
+ code_model=code_model,
428
+ parameters=ConfigGlobalParameterList.from_yaml(yaml_data, code_model),
429
+ )
@@ -0,0 +1,239 @@
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 typing import List, Dict, Any, Set, Union, Literal
7
+
8
+ from .base import BaseType
9
+ from .enum_type import EnumType
10
+ from .model_type import ModelType
11
+ from .combined_type import CombinedType
12
+ from .client import Client
13
+ from .request_builder import RequestBuilder, OverloadedRequestBuilder
14
+
15
+
16
+ def _is_legacy(options) -> bool:
17
+ return not (options.get("version_tolerant") or options.get("low_level_client"))
18
+
19
+
20
+ class CodeModel: # pylint: disable=too-many-public-methods, disable=too-many-instance-attributes
21
+ """Top level code model
22
+
23
+ :param options: Options of the code model. I.e., whether this is for management generation
24
+ :type options: dict[str, bool]
25
+ :param str module_name: The module name for the client. Is in snake case.
26
+ :param str class_name: The class name for the client. Is in pascal case.
27
+ :param str description: The description of the client
28
+ :param str namespace: The namespace of our module
29
+ :param schemas: The list of schemas we are going to serialize in the models files. Maps their yaml
30
+ id to our created ModelType.
31
+ :type schemas: dict[int, ~autorest.models.ModelType]
32
+ :param sorted_schemas: Our schemas in order by inheritance and alphabet
33
+ :type sorted_schemas: list[~autorest.models.ModelType]
34
+ :param enums: The enums, if any, we are going to serialize. Maps their yaml id to our created EnumType.
35
+ :type enums: Dict[int, ~autorest.models.EnumType]
36
+ :param primitives: List of schemas we've created that are not EnumSchemas or ObjectSchemas. Maps their
37
+ yaml id to our created schemas.
38
+ :type primitives: Dict[int, ~autorest.models.BaseType]
39
+ :param package_dependency: All the dependencies needed in setup.py
40
+ :type package_dependency: Dict[str, str]
41
+ """
42
+
43
+ def __init__(
44
+ self,
45
+ yaml_data: Dict[str, Any],
46
+ options: Dict[str, Any],
47
+ *,
48
+ is_subnamespace: bool = False,
49
+ ) -> None:
50
+ self.yaml_data = yaml_data
51
+ self.options = options
52
+ self.namespace = self.yaml_data["namespace"]
53
+ self.types_map: Dict[int, BaseType] = {} # map yaml id to schema
54
+ self._model_types: List[ModelType] = []
55
+ from . import build_type
56
+
57
+ for type_yaml in yaml_data.get("types", []):
58
+ build_type(yaml_data=type_yaml, code_model=self)
59
+ self.clients: List[Client] = [
60
+ Client.from_yaml(client_yaml_data, self) for client_yaml_data in yaml_data["clients"]
61
+ ]
62
+ self.subnamespace_to_clients: Dict[str, List[Client]] = {
63
+ subnamespace: [Client.from_yaml(client_yaml, self, is_subclient=True) for client_yaml in client_yamls]
64
+ for subnamespace, client_yamls in yaml_data.get("subnamespaceToClients", {}).items()
65
+ }
66
+ if self.options["models_mode"] and self.model_types:
67
+ self.sort_model_types()
68
+ self.is_subnamespace = is_subnamespace
69
+ self.named_unions: List[CombinedType] = [
70
+ t for t in self.types_map.values() if isinstance(t, CombinedType) and t.name
71
+ ]
72
+ self.cross_language_package_id = self.yaml_data.get("crossLanguagePackageId")
73
+ self.for_test: bool = False
74
+
75
+ @property
76
+ def has_form_data(self) -> bool:
77
+ return any(og.has_form_data_body for client in self.clients for og in client.operation_groups)
78
+
79
+ @property
80
+ def has_etag(self) -> bool:
81
+ return any(client.has_etag for client in self.clients)
82
+
83
+ @property
84
+ def has_operations(self) -> bool:
85
+ if any(c for c in self.clients if c.has_operations):
86
+ return True
87
+ return any(c for clients in self.subnamespace_to_clients.values() for c in clients if c.has_operations)
88
+
89
+ @property
90
+ def has_non_abstract_operations(self) -> bool:
91
+ return any(c for c in self.clients if c.has_non_abstract_operations) or any(
92
+ c for cs in self.subnamespace_to_clients.values() for c in cs if c.has_non_abstract_operations
93
+ )
94
+
95
+ def lookup_request_builder(self, request_builder_id: int) -> Union[RequestBuilder, OverloadedRequestBuilder]:
96
+ """Find the request builder based off of id"""
97
+ for client in self.clients:
98
+ try:
99
+ return client.lookup_request_builder(request_builder_id)
100
+ except KeyError:
101
+ pass
102
+ raise KeyError(f"No request builder with id {request_builder_id} found.")
103
+
104
+ @property
105
+ def is_azure_flavor(self) -> bool:
106
+ return self.options["flavor"] == "azure"
107
+
108
+ @property
109
+ def rest_layer_name(self) -> str:
110
+ """If we have a separate rest layer, what is its name?"""
111
+ return "rest" if self.options["builders_visibility"] == "public" else "_rest"
112
+
113
+ @property
114
+ def client_filename(self) -> str:
115
+ return self.clients[0].filename
116
+
117
+ def need_vendored_code(self, async_mode: bool) -> bool:
118
+ """Whether we need to vendor code in the _vendor.py file for this SDK"""
119
+ if self.has_abstract_operations:
120
+ return True
121
+ if async_mode:
122
+ return self.need_mixin_abc
123
+ return self.need_mixin_abc or self.has_etag or self.has_form_data
124
+
125
+ @property
126
+ def need_mixin_abc(self) -> bool:
127
+ return any(c for c in self.clients if c.has_mixin)
128
+
129
+ @property
130
+ def has_abstract_operations(self) -> bool:
131
+ return any(c for c in self.clients if c.has_abstract_operations)
132
+
133
+ @property
134
+ def operations_folder_name(self) -> str:
135
+ """Get the name of the operations folder that holds operations."""
136
+ name = "operations"
137
+ if self.options["version_tolerant"] and not any(
138
+ og for client in self.clients for og in client.operation_groups if not og.is_mixin
139
+ ):
140
+ name = f"_{name}"
141
+ return name
142
+
143
+ @property
144
+ def description(self) -> str:
145
+ return self.clients[0].description
146
+
147
+ def lookup_type(self, schema_id: int) -> BaseType:
148
+ """Looks to see if the schema has already been created.
149
+
150
+ :param int schema_id: The yaml id of the schema
151
+ :return: If created, we return the created schema, otherwise, we throw.
152
+ :rtype: ~autorest.models.BaseType
153
+ :raises: KeyError if schema is not found
154
+ """
155
+ try:
156
+ return next(type for id, type in self.types_map.items() if id == schema_id)
157
+ except StopIteration as exc:
158
+ raise KeyError(f"Couldn't find schema with id {schema_id}") from exc
159
+
160
+ @property
161
+ def model_types(self) -> List[ModelType]:
162
+ """All of the model types in this class"""
163
+ if not self._model_types:
164
+ self._model_types = [
165
+ t
166
+ for t in self.types_map.values()
167
+ if isinstance(t, ModelType) and not (self.options["models_mode"] == "dpg" and t.page_result_model)
168
+ ]
169
+ return self._model_types
170
+
171
+ @model_types.setter
172
+ def model_types(self, val: List[ModelType]) -> None:
173
+ self._model_types = val
174
+
175
+ @property
176
+ def public_model_types(self) -> List[ModelType]:
177
+ return [m for m in self.model_types if not m.internal and not m.base == "json"]
178
+
179
+ @property
180
+ def enums(self) -> List[EnumType]:
181
+ """All of the enums"""
182
+ return [t for t in self.types_map.values() if isinstance(t, EnumType)]
183
+
184
+ @property
185
+ def core_library(self) -> Literal["azure.core", "corehttp"]:
186
+ return "azure.core" if self.is_azure_flavor else "corehttp"
187
+
188
+ def _sort_model_types_helper(
189
+ self,
190
+ current: ModelType,
191
+ seen_schema_names: Set[str],
192
+ seen_schema_yaml_ids: Set[int],
193
+ ):
194
+ if current.id in seen_schema_yaml_ids:
195
+ return []
196
+ if current.name in seen_schema_names:
197
+ raise ValueError(f"We have already generated a schema with name {current.name}")
198
+ ancestors = [current]
199
+ if current.parents:
200
+ for parent in current.parents:
201
+ if parent.id in seen_schema_yaml_ids:
202
+ continue
203
+ seen_schema_names.add(current.name)
204
+ seen_schema_yaml_ids.add(current.id)
205
+ ancestors = self._sort_model_types_helper(parent, seen_schema_names, seen_schema_yaml_ids) + ancestors
206
+ seen_schema_names.add(current.name)
207
+ seen_schema_yaml_ids.add(current.id)
208
+ return ancestors
209
+
210
+ def sort_model_types(self) -> None:
211
+ """Sorts the final object schemas by inheritance and by alphabetical order.
212
+
213
+ :return: None
214
+ :rtype: None
215
+ """
216
+ seen_schema_names: Set[str] = set()
217
+ seen_schema_yaml_ids: Set[int] = set()
218
+ sorted_object_schemas: List[ModelType] = []
219
+ for schema in sorted(self.model_types, key=lambda x: x.name.lower()):
220
+ sorted_object_schemas.extend(self._sort_model_types_helper(schema, seen_schema_names, seen_schema_yaml_ids))
221
+ self.model_types = sorted_object_schemas
222
+
223
+ @property
224
+ def models_filename(self) -> str:
225
+ """Get the names of the model file(s)"""
226
+ if self.is_legacy:
227
+ return "_models_py3"
228
+ return "_models"
229
+
230
+ @property
231
+ def enums_filename(self) -> str:
232
+ """The name of the enums file"""
233
+ if self.is_legacy:
234
+ return f"_{self.clients[0].legacy_filename}_enums"
235
+ return "_enums"
236
+
237
+ @property
238
+ def is_legacy(self) -> bool:
239
+ return _is_legacy(self.options)