@typespec/http-client-python 0.4.4 → 0.5.0

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