@typespec/http-client-python 0.5.1 → 0.6.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.
- package/dist/emitter/code-model.d.ts.map +1 -1
- package/dist/emitter/code-model.js +10 -7
- package/dist/emitter/code-model.js.map +1 -1
- package/dist/emitter/emitter.d.ts.map +1 -1
- package/dist/emitter/emitter.js +4 -1
- package/dist/emitter/emitter.js.map +1 -1
- package/dist/emitter/lib.d.ts +1 -0
- package/dist/emitter/lib.d.ts.map +1 -1
- package/dist/emitter/lib.js +1 -0
- package/dist/emitter/lib.js.map +1 -1
- package/dist/emitter/types.d.ts.map +1 -1
- package/dist/emitter/types.js +7 -4
- package/dist/emitter/types.js.map +1 -1
- package/dist/emitter/utils.d.ts +1 -0
- package/dist/emitter/utils.d.ts.map +1 -1
- package/dist/emitter/utils.js +19 -0
- package/dist/emitter/utils.js.map +1 -1
- package/emitter/src/code-model.ts +16 -6
- package/emitter/src/emitter.ts +4 -1
- package/emitter/src/lib.ts +4 -0
- package/emitter/src/types.ts +16 -4
- package/emitter/src/utils.ts +27 -0
- package/emitter/temp/tsconfig.tsbuildinfo +1 -1
- package/eng/scripts/ci/regenerate.ts +7 -0
- package/eng/scripts/setup/__pycache__/venvtools.cpython-38.pyc +0 -0
- package/generator/build/lib/pygen/black.py +2 -2
- package/generator/build/lib/pygen/codegen/__init__.py +2 -0
- package/generator/build/lib/pygen/codegen/_utils.py +4 -0
- package/generator/build/lib/pygen/codegen/models/base.py +2 -3
- package/generator/build/lib/pygen/codegen/models/base_builder.py +5 -3
- package/generator/build/lib/pygen/codegen/models/client.py +28 -19
- package/generator/build/lib/pygen/codegen/models/code_model.py +200 -33
- package/generator/build/lib/pygen/codegen/models/combined_type.py +8 -5
- package/generator/build/lib/pygen/codegen/models/constant_type.py +2 -3
- package/generator/build/lib/pygen/codegen/models/credential_types.py +2 -3
- package/generator/build/lib/pygen/codegen/models/dictionary_type.py +2 -3
- package/generator/build/lib/pygen/codegen/models/enum_type.py +47 -24
- package/generator/build/lib/pygen/codegen/models/imports.py +14 -12
- package/generator/build/lib/pygen/codegen/models/list_type.py +2 -3
- package/generator/build/lib/pygen/codegen/models/lro_operation.py +8 -4
- package/generator/build/lib/pygen/codegen/models/lro_paging_operation.py +2 -2
- package/generator/build/lib/pygen/codegen/models/model_type.py +34 -19
- package/generator/build/lib/pygen/codegen/models/operation.py +66 -29
- package/generator/build/lib/pygen/codegen/models/operation_group.py +56 -11
- package/generator/build/lib/pygen/codegen/models/paging_operation.py +9 -6
- package/generator/build/lib/pygen/codegen/models/parameter.py +10 -10
- package/generator/build/lib/pygen/codegen/models/parameter_list.py +7 -7
- package/generator/build/lib/pygen/codegen/models/primitive_types.py +23 -43
- package/generator/build/lib/pygen/codegen/models/property.py +7 -7
- package/generator/build/lib/pygen/codegen/models/request_builder.py +9 -15
- package/generator/build/lib/pygen/codegen/models/response.py +6 -8
- package/generator/build/lib/pygen/codegen/models/utils.py +11 -0
- package/generator/build/lib/pygen/codegen/serializers/__init__.py +201 -242
- package/generator/build/lib/pygen/codegen/serializers/base_serializer.py +19 -1
- package/generator/build/lib/pygen/codegen/serializers/builder_serializer.py +53 -35
- package/generator/build/lib/pygen/codegen/serializers/client_serializer.py +9 -5
- package/generator/build/lib/pygen/codegen/serializers/enum_serializer.py +17 -3
- package/generator/build/lib/pygen/codegen/serializers/general_serializer.py +26 -14
- package/generator/build/lib/pygen/codegen/serializers/metadata_serializer.py +26 -8
- package/generator/build/lib/pygen/codegen/serializers/model_init_serializer.py +9 -4
- package/generator/build/lib/pygen/codegen/serializers/model_serializer.py +63 -23
- package/generator/build/lib/pygen/codegen/serializers/operation_groups_serializer.py +19 -16
- package/generator/build/lib/pygen/codegen/serializers/operations_init_serializer.py +5 -10
- package/generator/build/lib/pygen/codegen/serializers/parameter_serializer.py +10 -7
- package/generator/build/lib/pygen/codegen/serializers/request_builders_serializer.py +10 -1
- package/generator/build/lib/pygen/codegen/serializers/sample_serializer.py +7 -10
- package/generator/build/lib/pygen/codegen/serializers/test_serializer.py +24 -28
- package/generator/build/lib/pygen/codegen/serializers/types_serializer.py +6 -1
- package/generator/build/lib/pygen/codegen/serializers/utils.py +1 -15
- package/generator/build/lib/pygen/codegen/templates/client_container.py.jinja2 +1 -1
- package/generator/build/lib/pygen/codegen/templates/config_container.py.jinja2 +1 -1
- package/generator/build/lib/pygen/codegen/templates/enum_container.py.jinja2 +1 -1
- package/generator/build/lib/pygen/codegen/templates/init.py.jinja2 +1 -1
- package/generator/build/lib/pygen/codegen/templates/model_container.py.jinja2 +1 -1
- package/generator/build/lib/pygen/codegen/templates/operations_folder_init.py.jinja2 +2 -4
- package/generator/build/lib/pygen/codegen/templates/test.py.jinja2 +3 -3
- package/generator/build/lib/pygen/codegen/templates/testpreparer.py.jinja2 +2 -2
- package/generator/build/lib/pygen/codegen/templates/vendor.py.jinja2 +4 -4
- package/generator/build/lib/pygen/preprocess/__init__.py +0 -4
- package/generator/component-detection-pip-report.json +2 -2
- package/generator/dev_requirements.txt +2 -2
- package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
- package/generator/pygen/black.py +2 -2
- package/generator/pygen/codegen/__init__.py +2 -0
- package/generator/pygen/codegen/_utils.py +4 -0
- package/generator/pygen/codegen/models/base.py +2 -3
- package/generator/pygen/codegen/models/base_builder.py +5 -3
- package/generator/pygen/codegen/models/client.py +28 -19
- package/generator/pygen/codegen/models/code_model.py +200 -33
- package/generator/pygen/codegen/models/combined_type.py +8 -5
- package/generator/pygen/codegen/models/constant_type.py +2 -3
- package/generator/pygen/codegen/models/credential_types.py +2 -3
- package/generator/pygen/codegen/models/dictionary_type.py +2 -3
- package/generator/pygen/codegen/models/enum_type.py +47 -24
- package/generator/pygen/codegen/models/imports.py +14 -12
- package/generator/pygen/codegen/models/list_type.py +2 -3
- package/generator/pygen/codegen/models/lro_operation.py +8 -4
- package/generator/pygen/codegen/models/lro_paging_operation.py +2 -2
- package/generator/pygen/codegen/models/model_type.py +34 -19
- package/generator/pygen/codegen/models/operation.py +66 -29
- package/generator/pygen/codegen/models/operation_group.py +56 -11
- package/generator/pygen/codegen/models/paging_operation.py +9 -6
- package/generator/pygen/codegen/models/parameter.py +10 -10
- package/generator/pygen/codegen/models/parameter_list.py +7 -7
- package/generator/pygen/codegen/models/primitive_types.py +23 -43
- package/generator/pygen/codegen/models/property.py +7 -7
- package/generator/pygen/codegen/models/request_builder.py +9 -15
- package/generator/pygen/codegen/models/response.py +6 -8
- package/generator/pygen/codegen/models/utils.py +11 -0
- package/generator/pygen/codegen/serializers/__init__.py +201 -242
- package/generator/pygen/codegen/serializers/base_serializer.py +19 -1
- package/generator/pygen/codegen/serializers/builder_serializer.py +53 -35
- package/generator/pygen/codegen/serializers/client_serializer.py +9 -5
- package/generator/pygen/codegen/serializers/enum_serializer.py +17 -3
- package/generator/pygen/codegen/serializers/general_serializer.py +26 -14
- package/generator/pygen/codegen/serializers/metadata_serializer.py +26 -8
- package/generator/pygen/codegen/serializers/model_init_serializer.py +9 -4
- package/generator/pygen/codegen/serializers/model_serializer.py +63 -23
- package/generator/pygen/codegen/serializers/operation_groups_serializer.py +19 -16
- package/generator/pygen/codegen/serializers/operations_init_serializer.py +5 -10
- package/generator/pygen/codegen/serializers/parameter_serializer.py +10 -7
- package/generator/pygen/codegen/serializers/request_builders_serializer.py +10 -1
- package/generator/pygen/codegen/serializers/sample_serializer.py +7 -10
- package/generator/pygen/codegen/serializers/test_serializer.py +24 -28
- package/generator/pygen/codegen/serializers/types_serializer.py +6 -1
- package/generator/pygen/codegen/serializers/utils.py +1 -15
- package/generator/pygen/codegen/templates/client_container.py.jinja2 +1 -1
- package/generator/pygen/codegen/templates/config_container.py.jinja2 +1 -1
- package/generator/pygen/codegen/templates/enum_container.py.jinja2 +1 -1
- package/generator/pygen/codegen/templates/init.py.jinja2 +1 -1
- package/generator/pygen/codegen/templates/model_container.py.jinja2 +1 -1
- package/generator/pygen/codegen/templates/operations_folder_init.py.jinja2 +2 -4
- package/generator/pygen/codegen/templates/test.py.jinja2 +3 -3
- package/generator/pygen/codegen/templates/testpreparer.py.jinja2 +2 -2
- package/generator/pygen/codegen/templates/vendor.py.jinja2 +4 -4
- package/generator/pygen/preprocess/__init__.py +0 -4
- package/generator/test/azure/mock_api_tests/asynctests/test_azure_client_generator_core_access_async.py +1 -1
- package/generator/test/azure/mock_api_tests/asynctests/test_client_namespace_async.py +31 -0
- package/generator/test/azure/mock_api_tests/test_azure_client_generator_core_access.py +1 -1
- package/generator/test/azure/mock_api_tests/test_client_namespace.py +29 -0
- package/generator/test/azure/mock_api_tests/test_resiliency_srv_driven_async.py +1 -0
- package/generator/test/azure/requirements.txt +3 -2
- package/generator/test/azure/tox.ini +2 -2
- package/generator/test/unbranded/requirements.txt +2 -2
- package/generator/test/unbranded/tox.ini +2 -2
- package/package.json +1 -1
|
@@ -87,8 +87,7 @@ class BaseType(BaseModel, ABC): # pylint: disable=too-many-public-methods
|
|
|
87
87
|
attrs_list.append("'text': True")
|
|
88
88
|
return ", ".join(attrs_list)
|
|
89
89
|
|
|
90
|
-
|
|
91
|
-
def serialization_type(self) -> str:
|
|
90
|
+
def serialization_type(self, **kwargs: Any) -> str:
|
|
92
91
|
"""The tag recognized by 'msrest' as a serialization/deserialization.
|
|
93
92
|
|
|
94
93
|
'str', 'int', 'float', 'bool' or
|
|
@@ -103,7 +102,7 @@ class BaseType(BaseModel, ABC): # pylint: disable=too-many-public-methods
|
|
|
103
102
|
|
|
104
103
|
@property
|
|
105
104
|
def msrest_deserialization_key(self) -> str:
|
|
106
|
-
return self.serialization_type
|
|
105
|
+
return self.serialization_type()
|
|
107
106
|
|
|
108
107
|
@property
|
|
109
108
|
def client_default_value(self) -> Any:
|
|
@@ -14,6 +14,7 @@ from typing import (
|
|
|
14
14
|
Union,
|
|
15
15
|
TYPE_CHECKING,
|
|
16
16
|
cast,
|
|
17
|
+
Sequence,
|
|
17
18
|
)
|
|
18
19
|
from abc import abstractmethod
|
|
19
20
|
|
|
@@ -39,7 +40,7 @@ if TYPE_CHECKING:
|
|
|
39
40
|
from .request_builder import RequestBuilder
|
|
40
41
|
|
|
41
42
|
|
|
42
|
-
OverloadListType = TypeVar("OverloadListType", bound=Union[
|
|
43
|
+
OverloadListType = TypeVar("OverloadListType", bound=Union[Sequence["Operation"], Sequence["RequestBuilder"]])
|
|
43
44
|
|
|
44
45
|
_LOGGER = logging.getLogger(__name__)
|
|
45
46
|
|
|
@@ -72,6 +73,7 @@ class BaseBuilder(
|
|
|
72
73
|
self.api_versions: List[str] = yaml_data["apiVersions"]
|
|
73
74
|
self.added_on: Optional[str] = yaml_data.get("addedOn")
|
|
74
75
|
self.external_docs: Optional[Dict[str, Any]] = yaml_data.get("externalDocs")
|
|
76
|
+
self.client_namespace: str = yaml_data.get("clientNamespace", code_model.namespace)
|
|
75
77
|
|
|
76
78
|
if code_model.options["version_tolerant"] and yaml_data.get("abstract"):
|
|
77
79
|
_LOGGER.warning(
|
|
@@ -112,7 +114,7 @@ class BaseBuilder(
|
|
|
112
114
|
)
|
|
113
115
|
return self._description or self.name
|
|
114
116
|
|
|
115
|
-
def method_signature(self, async_mode: bool) -> List[str]:
|
|
117
|
+
def method_signature(self, async_mode: bool, **kwargs: Any) -> List[str]:
|
|
116
118
|
if self.abstract:
|
|
117
119
|
return ["*args,", "**kwargs"]
|
|
118
|
-
return self.parameters.method_signature(async_mode)
|
|
120
|
+
return self.parameters.method_signature(async_mode, **kwargs)
|
|
@@ -43,6 +43,7 @@ class _ClientConfigBase(Generic[ParameterListType], BaseModel):
|
|
|
43
43
|
self.parameters = parameters
|
|
44
44
|
self.url: str = self.yaml_data["url"] # the base endpoint of the client. Can be parameterized or not
|
|
45
45
|
self.legacy_filename: str = self.yaml_data.get("legacyFilename", "client")
|
|
46
|
+
self.client_namespace: str = self.yaml_data.get("clientNamespace", code_model.namespace)
|
|
46
47
|
|
|
47
48
|
@property
|
|
48
49
|
def description(self) -> str:
|
|
@@ -188,7 +189,7 @@ class Client(_ClientConfigBase[ClientGlobalParameterList]):
|
|
|
188
189
|
except StopIteration as exc:
|
|
189
190
|
raise KeyError(f"No operation with id {operation_id} found.") from exc
|
|
190
191
|
|
|
191
|
-
def _imports_shared(self, async_mode: bool) -> FileImport:
|
|
192
|
+
def _imports_shared(self, async_mode: bool, **kwargs) -> FileImport:
|
|
192
193
|
file_import = FileImport(self.code_model)
|
|
193
194
|
file_import.add_submodule_import("typing", "Any", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
194
195
|
if self.code_model.options["azure_arm"]:
|
|
@@ -206,8 +207,8 @@ class Client(_ClientConfigBase[ClientGlobalParameterList]):
|
|
|
206
207
|
file_import.merge(
|
|
207
208
|
gp.imports(
|
|
208
209
|
async_mode,
|
|
209
|
-
|
|
210
|
-
|
|
210
|
+
is_operation_file=True,
|
|
211
|
+
**kwargs,
|
|
211
212
|
)
|
|
212
213
|
)
|
|
213
214
|
file_import.add_submodule_import(
|
|
@@ -215,8 +216,9 @@ class Client(_ClientConfigBase[ClientGlobalParameterList]):
|
|
|
215
216
|
f"{self.name}Configuration",
|
|
216
217
|
ImportType.LOCAL,
|
|
217
218
|
)
|
|
219
|
+
serialize_namespace = kwargs.get("serialize_namespace", self.code_model.namespace)
|
|
218
220
|
file_import.add_msrest_import(
|
|
219
|
-
|
|
221
|
+
serialize_namespace=serialize_namespace,
|
|
220
222
|
msrest_import_type=MsrestImportType.SerializerDeserializer,
|
|
221
223
|
typing_section=TypingSection.REGULAR,
|
|
222
224
|
)
|
|
@@ -277,8 +279,8 @@ class Client(_ClientConfigBase[ClientGlobalParameterList]):
|
|
|
277
279
|
"""Whether there is non-abstract operation in any operation group."""
|
|
278
280
|
return any(og.has_non_abstract_operations for og in self.operation_groups)
|
|
279
281
|
|
|
280
|
-
def imports(self, async_mode: bool) -> FileImport:
|
|
281
|
-
file_import = self._imports_shared(async_mode)
|
|
282
|
+
def imports(self, async_mode: bool, **kwargs) -> FileImport:
|
|
283
|
+
file_import = self._imports_shared(async_mode, **kwargs)
|
|
282
284
|
if async_mode:
|
|
283
285
|
file_import.add_submodule_import("typing", "Awaitable", ImportType.STDLIB)
|
|
284
286
|
file_import.add_submodule_import(
|
|
@@ -300,9 +302,13 @@ class Client(_ClientConfigBase[ClientGlobalParameterList]):
|
|
|
300
302
|
ImportType.SDKCORE,
|
|
301
303
|
TypingSection.CONDITIONAL,
|
|
302
304
|
)
|
|
305
|
+
serialize_namespace = kwargs.get("serialize_namespace", self.code_model.namespace)
|
|
303
306
|
for og in self.operation_groups:
|
|
304
307
|
file_import.add_submodule_import(
|
|
305
|
-
|
|
308
|
+
self.code_model.get_relative_import_path(
|
|
309
|
+
serialize_namespace,
|
|
310
|
+
self.code_model.get_imported_namespace_for_operation(og.client_namespace, async_mode),
|
|
311
|
+
),
|
|
306
312
|
og.class_name,
|
|
307
313
|
ImportType.LOCAL,
|
|
308
314
|
)
|
|
@@ -317,8 +323,8 @@ class Client(_ClientConfigBase[ClientGlobalParameterList]):
|
|
|
317
323
|
file_import.add_submodule_import("copy", "deepcopy", ImportType.STDLIB)
|
|
318
324
|
return file_import
|
|
319
325
|
|
|
320
|
-
def imports_for_multiapi(self, async_mode: bool) -> FileImport:
|
|
321
|
-
file_import = self._imports_shared(async_mode)
|
|
326
|
+
def imports_for_multiapi(self, async_mode: bool, **kwargs) -> FileImport:
|
|
327
|
+
file_import = self._imports_shared(async_mode, **kwargs)
|
|
322
328
|
file_import.add_submodule_import("typing", "Optional", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
323
329
|
try:
|
|
324
330
|
mixin_operation = next(og for og in self.operation_groups if og.is_mixin)
|
|
@@ -377,7 +383,7 @@ class Config(_ClientConfigBase[ConfigGlobalParameterList]):
|
|
|
377
383
|
def name(self) -> str:
|
|
378
384
|
return f"{super().name}Configuration"
|
|
379
385
|
|
|
380
|
-
def _imports_shared(self, async_mode: bool) -> FileImport:
|
|
386
|
+
def _imports_shared(self, async_mode: bool, **kwargs: Any) -> FileImport:
|
|
381
387
|
file_import = FileImport(self.code_model)
|
|
382
388
|
file_import.add_submodule_import(
|
|
383
389
|
"pipeline" if self.code_model.is_azure_flavor else "runtime",
|
|
@@ -386,7 +392,12 @@ class Config(_ClientConfigBase[ConfigGlobalParameterList]):
|
|
|
386
392
|
)
|
|
387
393
|
file_import.add_submodule_import("typing", "Any", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
388
394
|
if self.code_model.options["package_version"]:
|
|
389
|
-
|
|
395
|
+
serialize_namespace = kwargs.get("serialize_namespace", self.code_model.namespace)
|
|
396
|
+
file_import.add_submodule_import(
|
|
397
|
+
self.code_model.get_relative_import_path(serialize_namespace, module_name="_version"),
|
|
398
|
+
"VERSION",
|
|
399
|
+
ImportType.LOCAL,
|
|
400
|
+
)
|
|
390
401
|
if self.code_model.options["azure_arm"]:
|
|
391
402
|
policy = "AsyncARMChallengeAuthenticationPolicy" if async_mode else "ARMChallengeAuthenticationPolicy"
|
|
392
403
|
file_import.add_submodule_import("azure.mgmt.core.policies", "ARMHttpLoggingPolicy", ImportType.SDKCORE)
|
|
@@ -394,22 +405,21 @@ class Config(_ClientConfigBase[ConfigGlobalParameterList]):
|
|
|
394
405
|
|
|
395
406
|
return file_import
|
|
396
407
|
|
|
397
|
-
def imports(self, async_mode: bool) -> FileImport:
|
|
398
|
-
file_import = self._imports_shared(async_mode)
|
|
408
|
+
def imports(self, async_mode: bool, **kwargs) -> FileImport:
|
|
409
|
+
file_import = self._imports_shared(async_mode, **kwargs)
|
|
399
410
|
for gp in self.parameters:
|
|
400
411
|
if gp.method_location == ParameterMethodLocation.KWARG and gp not in self.parameters.kwargs_to_pop:
|
|
401
412
|
continue
|
|
402
413
|
file_import.merge(
|
|
403
414
|
gp.imports(
|
|
404
415
|
async_mode=async_mode,
|
|
405
|
-
|
|
406
|
-
operation=True,
|
|
416
|
+
**kwargs,
|
|
407
417
|
)
|
|
408
418
|
)
|
|
409
419
|
return file_import
|
|
410
420
|
|
|
411
|
-
def imports_for_multiapi(self, async_mode: bool) -> FileImport:
|
|
412
|
-
file_import = self._imports_shared(async_mode)
|
|
421
|
+
def imports_for_multiapi(self, async_mode: bool, **kwargs: Any) -> FileImport:
|
|
422
|
+
file_import = self._imports_shared(async_mode, **kwargs)
|
|
413
423
|
for gp in self.parameters:
|
|
414
424
|
if (
|
|
415
425
|
gp.method_location == ParameterMethodLocation.KWARG
|
|
@@ -420,8 +430,7 @@ class Config(_ClientConfigBase[ConfigGlobalParameterList]):
|
|
|
420
430
|
file_import.merge(
|
|
421
431
|
gp.imports_for_multiapi(
|
|
422
432
|
async_mode=async_mode,
|
|
423
|
-
|
|
424
|
-
operation=True,
|
|
433
|
+
**kwargs,
|
|
425
434
|
)
|
|
426
435
|
)
|
|
427
436
|
return file_import
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
# Licensed under the MIT License. See License.txt in the project root for
|
|
4
4
|
# license information.
|
|
5
5
|
# --------------------------------------------------------------------------
|
|
6
|
-
from typing import List, Dict, Any, Set, Union, Literal
|
|
6
|
+
from typing import List, Dict, Any, Set, Union, Literal, Optional, cast
|
|
7
7
|
|
|
8
8
|
from .base import BaseType
|
|
9
9
|
from .enum_type import EnumType
|
|
@@ -11,12 +11,40 @@ from .model_type import ModelType, UsageFlags
|
|
|
11
11
|
from .combined_type import CombinedType
|
|
12
12
|
from .client import Client
|
|
13
13
|
from .request_builder import RequestBuilder, OverloadedRequestBuilder
|
|
14
|
+
from .operation_group import OperationGroup
|
|
15
|
+
from .utils import NamespaceType
|
|
14
16
|
|
|
15
17
|
|
|
16
18
|
def _is_legacy(options) -> bool:
|
|
17
19
|
return not (options.get("version_tolerant") or options.get("low_level_client"))
|
|
18
20
|
|
|
19
21
|
|
|
22
|
+
def get_all_operation_groups_recursively(clients: List[Client]) -> List[OperationGroup]:
|
|
23
|
+
operation_groups = []
|
|
24
|
+
queue = []
|
|
25
|
+
for client in clients:
|
|
26
|
+
queue.extend(client.operation_groups)
|
|
27
|
+
while queue:
|
|
28
|
+
operation_groups.append(queue.pop(0))
|
|
29
|
+
if operation_groups[-1].operation_groups:
|
|
30
|
+
queue.extend(operation_groups[-1].operation_groups)
|
|
31
|
+
return operation_groups
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class ClientNamespaceType:
|
|
35
|
+
def __init__(
|
|
36
|
+
self,
|
|
37
|
+
clients: Optional[List[Client]] = None,
|
|
38
|
+
models: Optional[List[ModelType]] = None,
|
|
39
|
+
enums: Optional[List[EnumType]] = None,
|
|
40
|
+
operation_groups: Optional[List[OperationGroup]] = None,
|
|
41
|
+
):
|
|
42
|
+
self.clients = clients or []
|
|
43
|
+
self.models = models or []
|
|
44
|
+
self.enums = enums or []
|
|
45
|
+
self.operation_groups = operation_groups or []
|
|
46
|
+
|
|
47
|
+
|
|
20
48
|
class CodeModel: # pylint: disable=too-many-public-methods, disable=too-many-instance-attributes
|
|
21
49
|
"""Top level code model
|
|
22
50
|
|
|
@@ -44,8 +72,6 @@ class CodeModel: # pylint: disable=too-many-public-methods, disable=too-many-in
|
|
|
44
72
|
self,
|
|
45
73
|
yaml_data: Dict[str, Any],
|
|
46
74
|
options: Dict[str, Any],
|
|
47
|
-
*,
|
|
48
|
-
is_subnamespace: bool = False,
|
|
49
75
|
) -> None:
|
|
50
76
|
self.yaml_data = yaml_data
|
|
51
77
|
self.options = options
|
|
@@ -59,18 +85,113 @@ class CodeModel: # pylint: disable=too-many-public-methods, disable=too-many-in
|
|
|
59
85
|
self.clients: List[Client] = [
|
|
60
86
|
Client.from_yaml(client_yaml_data, self) for client_yaml_data in yaml_data["clients"]
|
|
61
87
|
]
|
|
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
88
|
if self.options["models_mode"] and self.model_types:
|
|
67
89
|
self.sort_model_types()
|
|
68
|
-
self.is_subnamespace = is_subnamespace
|
|
69
90
|
self.named_unions: List[CombinedType] = [
|
|
70
91
|
t for t in self.types_map.values() if isinstance(t, CombinedType) and t.name
|
|
71
92
|
]
|
|
72
93
|
self.cross_language_package_id = self.yaml_data.get("crossLanguagePackageId")
|
|
73
94
|
self.for_test: bool = False
|
|
95
|
+
# key is typespec namespace, value is models/clients/opeartion_groups/enums cache in the namespace
|
|
96
|
+
self._client_namespace_types: Dict[str, ClientNamespaceType] = {}
|
|
97
|
+
self.has_subnamespace = False
|
|
98
|
+
self._operations_folder_name: Dict[str, str] = {}
|
|
99
|
+
self._relative_import_path: Dict[str, str] = {}
|
|
100
|
+
|
|
101
|
+
@staticmethod
|
|
102
|
+
def get_imported_namespace_for_client(imported_namespace: str, async_mode: bool = False) -> str:
|
|
103
|
+
return imported_namespace + (".aio" if async_mode else "")
|
|
104
|
+
|
|
105
|
+
@staticmethod
|
|
106
|
+
def get_imported_namespace_for_model(imported_namespace: str) -> str:
|
|
107
|
+
return imported_namespace + ".models"
|
|
108
|
+
|
|
109
|
+
def get_imported_namespace_for_operation(self, imported_namespace: str, async_mode: bool = False) -> str:
|
|
110
|
+
module_namespace = f".{self.operations_folder_name(imported_namespace)}"
|
|
111
|
+
return self.get_imported_namespace_for_client(imported_namespace, async_mode) + module_namespace
|
|
112
|
+
|
|
113
|
+
# | serialize_namespace | imported_namespace | relative_import_path |
|
|
114
|
+
# |----------------------|----------------------|----------------------|
|
|
115
|
+
# |azure.test.operations | azure.test.operations| . |
|
|
116
|
+
# |azure.test.operations | azure.test | .. |
|
|
117
|
+
# |azure.test.operations | azure.test.subtest | ..subtest |
|
|
118
|
+
# |azure.test.operations | azure | ... |
|
|
119
|
+
# |azure.test.aio.operations | azure.test | ... |
|
|
120
|
+
# |azure.test.subtest.aio.operations|azure.test | .... |
|
|
121
|
+
# |azure.test |azure.test.subtest | .subtest |
|
|
122
|
+
def get_relative_import_path(
|
|
123
|
+
self,
|
|
124
|
+
serialize_namespace: str,
|
|
125
|
+
imported_namespace: Optional[str] = None,
|
|
126
|
+
module_name: Optional[str] = None,
|
|
127
|
+
) -> str:
|
|
128
|
+
if imported_namespace is None:
|
|
129
|
+
imported_namespace = self.namespace
|
|
130
|
+
|
|
131
|
+
key = f"{serialize_namespace}-{imported_namespace}"
|
|
132
|
+
if key not in self._relative_import_path:
|
|
133
|
+
idx = 0
|
|
134
|
+
serialize_namespace_split = serialize_namespace.split(".")
|
|
135
|
+
imported_namespace_split = cast(str, imported_namespace).split(".")
|
|
136
|
+
while idx < min(len(serialize_namespace_split), len(imported_namespace_split)):
|
|
137
|
+
if serialize_namespace_split[idx] != imported_namespace_split[idx]:
|
|
138
|
+
break
|
|
139
|
+
idx += 1
|
|
140
|
+
self._relative_import_path[key] = "." * (len(serialize_namespace_split[idx:]) + 1) + ".".join(
|
|
141
|
+
imported_namespace_split[idx:]
|
|
142
|
+
)
|
|
143
|
+
result = self._relative_import_path[key]
|
|
144
|
+
if module_name is None:
|
|
145
|
+
return result
|
|
146
|
+
return f"{result}{module_name}" if result.endswith(".") else f"{result}.{module_name}"
|
|
147
|
+
|
|
148
|
+
@property
|
|
149
|
+
def need_unique_model_alias(self) -> bool:
|
|
150
|
+
return self.has_subnamespace and self.options["enable_typespec_namespace"]
|
|
151
|
+
|
|
152
|
+
def get_unique_models_alias(self, serialize_namespace: str, imported_namespace: str) -> str:
|
|
153
|
+
if not self.need_unique_model_alias:
|
|
154
|
+
return "_models"
|
|
155
|
+
relative_path = self.get_relative_import_path(
|
|
156
|
+
serialize_namespace, self.get_imported_namespace_for_model(imported_namespace)
|
|
157
|
+
)
|
|
158
|
+
dot_num = max(relative_path.count(".") - 1, 0)
|
|
159
|
+
parts = [""] + ([p for p in relative_path.split(".") if p] or ["models"])
|
|
160
|
+
return "_".join(parts) + (str(dot_num) if dot_num > 0 else "")
|
|
161
|
+
|
|
162
|
+
@property
|
|
163
|
+
def client_namespace_types(self) -> Dict[str, ClientNamespaceType]:
|
|
164
|
+
if not self._client_namespace_types:
|
|
165
|
+
# calculate client namespace types for each kind of client namespace
|
|
166
|
+
for client in self.clients:
|
|
167
|
+
if client.client_namespace not in self._client_namespace_types:
|
|
168
|
+
self._client_namespace_types[client.client_namespace] = ClientNamespaceType()
|
|
169
|
+
self._client_namespace_types[client.client_namespace].clients.append(client)
|
|
170
|
+
for model in self.model_types:
|
|
171
|
+
if model.client_namespace not in self._client_namespace_types:
|
|
172
|
+
self._client_namespace_types[model.client_namespace] = ClientNamespaceType()
|
|
173
|
+
self._client_namespace_types[model.client_namespace].models.append(model)
|
|
174
|
+
for enum in self.enums:
|
|
175
|
+
if enum.client_namespace not in self._client_namespace_types:
|
|
176
|
+
self._client_namespace_types[enum.client_namespace] = ClientNamespaceType()
|
|
177
|
+
self._client_namespace_types[enum.client_namespace].enums.append(enum)
|
|
178
|
+
for operation_group in get_all_operation_groups_recursively(self.clients):
|
|
179
|
+
if operation_group.client_namespace not in self._client_namespace_types:
|
|
180
|
+
self._client_namespace_types[operation_group.client_namespace] = ClientNamespaceType()
|
|
181
|
+
self._client_namespace_types[operation_group.client_namespace].operation_groups.append(operation_group)
|
|
182
|
+
|
|
183
|
+
# here we can check and record whether there are multi kinds of client namespace
|
|
184
|
+
if len(self._client_namespace_types.keys()) > 1:
|
|
185
|
+
self.has_subnamespace = True
|
|
186
|
+
|
|
187
|
+
# insert namespace to make sure it is continuous(e.g. ("", "azure", "azure.mgmt", "azure.mgmt.service"))
|
|
188
|
+
longest_namespace = sorted(self._client_namespace_types.keys())[-1]
|
|
189
|
+
namespace_parts = longest_namespace.split(".")
|
|
190
|
+
for idx in range(len(namespace_parts) + 1):
|
|
191
|
+
namespace = ".".join(namespace_parts[:idx])
|
|
192
|
+
if namespace not in self._client_namespace_types:
|
|
193
|
+
self._client_namespace_types[namespace] = ClientNamespaceType()
|
|
194
|
+
return self._client_namespace_types
|
|
74
195
|
|
|
75
196
|
@property
|
|
76
197
|
def has_form_data(self) -> bool:
|
|
@@ -80,17 +201,17 @@ class CodeModel: # pylint: disable=too-many-public-methods, disable=too-many-in
|
|
|
80
201
|
def has_etag(self) -> bool:
|
|
81
202
|
return any(client.has_etag for client in self.clients)
|
|
82
203
|
|
|
204
|
+
@staticmethod
|
|
205
|
+
def clients_has_operations(clients: List[Client]) -> bool:
|
|
206
|
+
return any(c for c in clients if c.has_operations)
|
|
207
|
+
|
|
83
208
|
@property
|
|
84
209
|
def has_operations(self) -> bool:
|
|
85
|
-
|
|
86
|
-
return True
|
|
87
|
-
return any(c for clients in self.subnamespace_to_clients.values() for c in clients if c.has_operations)
|
|
210
|
+
return self.clients_has_operations(self.clients)
|
|
88
211
|
|
|
89
212
|
@property
|
|
90
213
|
def has_non_abstract_operations(self) -> bool:
|
|
91
|
-
return any(c for c in self.clients if c.has_non_abstract_operations)
|
|
92
|
-
c for cs in self.subnamespace_to_clients.values() for c in cs if c.has_non_abstract_operations
|
|
93
|
-
)
|
|
214
|
+
return any(c for c in self.clients if c.has_non_abstract_operations)
|
|
94
215
|
|
|
95
216
|
def lookup_request_builder(self, request_builder_id: int) -> Union[RequestBuilder, OverloadedRequestBuilder]:
|
|
96
217
|
"""Find the request builder based off of id"""
|
|
@@ -114,31 +235,73 @@ class CodeModel: # pylint: disable=too-many-public-methods, disable=too-many-in
|
|
|
114
235
|
def client_filename(self) -> str:
|
|
115
236
|
return self.clients[0].filename
|
|
116
237
|
|
|
117
|
-
def
|
|
118
|
-
"""
|
|
119
|
-
|
|
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
|
|
238
|
+
def get_clients(self, client_namespace: str) -> List[Client]:
|
|
239
|
+
"""Get all clients in specific namespace"""
|
|
240
|
+
return self.client_namespace_types.get(client_namespace, ClientNamespaceType()).clients
|
|
124
241
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
242
|
+
def is_top_namespace(self, client_namespace: str) -> bool:
|
|
243
|
+
"""Whether the namespace is the top namespace. For example, a package named 'azure-mgmt-service',
|
|
244
|
+
'azure.mgmt.service' is the top namespace.
|
|
245
|
+
"""
|
|
246
|
+
return client_namespace == self.namespace
|
|
247
|
+
|
|
248
|
+
def need_vendored_code(self, async_mode: bool, client_namespace: str) -> bool:
|
|
249
|
+
"""Whether we need to vendor code in the _vendor.py in specific namespace"""
|
|
250
|
+
return (
|
|
251
|
+
self.need_vendored_form_data(async_mode, client_namespace)
|
|
252
|
+
or self.need_vendored_etag(client_namespace)
|
|
253
|
+
or self.need_vendored_abstract(client_namespace)
|
|
254
|
+
or self.need_vendored_mixin(client_namespace)
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
def need_vendored_form_data(self, async_mode: bool, client_namespace: str) -> bool:
|
|
258
|
+
return (
|
|
259
|
+
(not async_mode)
|
|
260
|
+
and self.is_top_namespace(client_namespace)
|
|
261
|
+
and self.has_form_data
|
|
262
|
+
and self.options["models_mode"] == "dpg"
|
|
263
|
+
)
|
|
264
|
+
|
|
265
|
+
def need_vendored_etag(self, client_namespace: str) -> bool:
|
|
266
|
+
return self.is_top_namespace(client_namespace) and self.has_etag
|
|
267
|
+
|
|
268
|
+
def need_vendored_abstract(self, client_namespace: str) -> bool:
|
|
269
|
+
return self.is_top_namespace(client_namespace) and self.has_abstract_operations
|
|
270
|
+
|
|
271
|
+
def need_vendored_mixin(self, client_namespace: str) -> bool:
|
|
272
|
+
return self.has_mixin(client_namespace)
|
|
273
|
+
|
|
274
|
+
def has_mixin(self, client_namespace: str) -> bool:
|
|
275
|
+
return any(c for c in self.get_clients(client_namespace) if c.has_mixin)
|
|
128
276
|
|
|
129
277
|
@property
|
|
130
278
|
def has_abstract_operations(self) -> bool:
|
|
131
279
|
return any(c for c in self.clients if c.has_abstract_operations)
|
|
132
280
|
|
|
133
|
-
|
|
134
|
-
def operations_folder_name(self) -> str:
|
|
281
|
+
def operations_folder_name(self, client_namespace: str) -> str:
|
|
135
282
|
"""Get the name of the operations folder that holds operations."""
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
283
|
+
if client_namespace not in self._operations_folder_name:
|
|
284
|
+
name = "operations"
|
|
285
|
+
operation_groups = self.client_namespace_types.get(client_namespace, ClientNamespaceType()).operation_groups
|
|
286
|
+
if self.options["version_tolerant"] and all(og.is_mixin for og in operation_groups):
|
|
287
|
+
name = f"_{name}"
|
|
288
|
+
self._operations_folder_name[client_namespace] = name
|
|
289
|
+
return self._operations_folder_name[client_namespace]
|
|
290
|
+
|
|
291
|
+
def get_serialize_namespace(
|
|
292
|
+
self,
|
|
293
|
+
client_namespace: str,
|
|
294
|
+
async_mode: bool = False,
|
|
295
|
+
client_namespace_type: NamespaceType = NamespaceType.CLIENT,
|
|
296
|
+
) -> str:
|
|
297
|
+
"""calculate the namespace for serialization from client namespace"""
|
|
298
|
+
if client_namespace_type == NamespaceType.CLIENT:
|
|
299
|
+
return client_namespace + (".aio" if async_mode else "")
|
|
300
|
+
if client_namespace_type == NamespaceType.MODEL:
|
|
301
|
+
return client_namespace + ".models"
|
|
302
|
+
|
|
303
|
+
operations_folder_name = self.operations_folder_name(client_namespace)
|
|
304
|
+
return client_namespace + (".aio." if async_mode else ".") + operations_folder_name
|
|
142
305
|
|
|
143
306
|
@property
|
|
144
307
|
def description(self) -> str:
|
|
@@ -170,9 +333,13 @@ class CodeModel: # pylint: disable=too-many-public-methods, disable=too-many-in
|
|
|
170
333
|
def model_types(self, val: List[ModelType]) -> None:
|
|
171
334
|
self._model_types = val
|
|
172
335
|
|
|
336
|
+
@staticmethod
|
|
337
|
+
def get_public_model_types(models: List[ModelType]) -> List[ModelType]:
|
|
338
|
+
return [m for m in models if not m.internal and not m.base == "json"]
|
|
339
|
+
|
|
173
340
|
@property
|
|
174
341
|
def public_model_types(self) -> List[ModelType]:
|
|
175
|
-
return
|
|
342
|
+
return self.get_public_model_types(self.model_types)
|
|
176
343
|
|
|
177
344
|
@property
|
|
178
345
|
def enums(self) -> List[EnumType]:
|
|
@@ -8,6 +8,7 @@ import re
|
|
|
8
8
|
from .imports import FileImport, ImportType, TypingSection
|
|
9
9
|
from .base import BaseType
|
|
10
10
|
from .model_type import ModelType
|
|
11
|
+
from .utils import NamespaceType
|
|
11
12
|
|
|
12
13
|
if TYPE_CHECKING:
|
|
13
14
|
from .code_model import CodeModel
|
|
@@ -30,9 +31,9 @@ class CombinedType(BaseType):
|
|
|
30
31
|
self.types = types # the types that this type is combining
|
|
31
32
|
self.name = yaml_data.get("name")
|
|
32
33
|
self._is_union_of_literals = all(i.type == "constant" for i in self.types)
|
|
34
|
+
self.client_namespace: str = self.yaml_data.get("clientNamespace", code_model.namespace)
|
|
33
35
|
|
|
34
|
-
|
|
35
|
-
def serialization_type(self) -> str:
|
|
36
|
+
def serialization_type(self, **kwargs: Any) -> str:
|
|
36
37
|
"""The tag recognized by 'msrest' as a serialization/deserialization.
|
|
37
38
|
|
|
38
39
|
'str', 'int', 'float', 'bool' or
|
|
@@ -45,7 +46,7 @@ class CombinedType(BaseType):
|
|
|
45
46
|
"""
|
|
46
47
|
if not all(t for t in self.types if t.type == "constant"):
|
|
47
48
|
raise ValueError("Shouldn't get serialization type of a combinedtype")
|
|
48
|
-
return self.types[0].serialization_type
|
|
49
|
+
return self.types[0].serialization_type(**kwargs)
|
|
49
50
|
|
|
50
51
|
@property
|
|
51
52
|
def client_default_value(self) -> Any:
|
|
@@ -112,9 +113,11 @@ class CombinedType(BaseType):
|
|
|
112
113
|
|
|
113
114
|
def imports(self, **kwargs: Any) -> FileImport:
|
|
114
115
|
file_import = FileImport(self.code_model)
|
|
115
|
-
|
|
116
|
+
serialize_namespace = kwargs.get("serialize_namespace", self.code_model.namespace)
|
|
117
|
+
serialize_namespace_type = kwargs.get("serialize_namespace_type")
|
|
118
|
+
if self.name and serialize_namespace_type != NamespaceType.TYPES_FILE:
|
|
116
119
|
file_import.add_submodule_import(
|
|
117
|
-
|
|
120
|
+
self.code_model.get_relative_import_path(serialize_namespace),
|
|
118
121
|
"_types",
|
|
119
122
|
ImportType.LOCAL,
|
|
120
123
|
TypingSection.TYPING,
|
|
@@ -56,14 +56,13 @@ class ConstantType(BaseType):
|
|
|
56
56
|
f"Default value is {self.get_declaration()}.",
|
|
57
57
|
)
|
|
58
58
|
|
|
59
|
-
|
|
60
|
-
def serialization_type(self) -> str:
|
|
59
|
+
def serialization_type(self, **kwargs: Any) -> str:
|
|
61
60
|
"""Returns the serialization value for msrest.
|
|
62
61
|
|
|
63
62
|
:return: The serialization value for msrest
|
|
64
63
|
:rtype: str
|
|
65
64
|
"""
|
|
66
|
-
return self.value_type.serialization_type
|
|
65
|
+
return self.value_type.serialization_type(**kwargs)
|
|
67
66
|
|
|
68
67
|
def docstring_text(self, **kwargs: Any) -> str:
|
|
69
68
|
return "constant"
|
|
@@ -131,8 +131,7 @@ class CredentialType(Generic[CredentialPolicyType], BaseType):
|
|
|
131
131
|
def docstring_text(self, **kwargs: Any) -> str:
|
|
132
132
|
return "credential"
|
|
133
133
|
|
|
134
|
-
|
|
135
|
-
def serialization_type(self) -> str:
|
|
134
|
+
def serialization_type(self, **kwargs: Any) -> str:
|
|
136
135
|
return self.docstring_type()
|
|
137
136
|
|
|
138
137
|
@classmethod
|
|
@@ -156,7 +155,7 @@ class TokenCredentialType(CredentialType[Union[BearerTokenCredentialPolicyType,
|
|
|
156
155
|
|
|
157
156
|
@property
|
|
158
157
|
def type_description(self) -> str:
|
|
159
|
-
return "
|
|
158
|
+
return "token credential"
|
|
160
159
|
|
|
161
160
|
@property
|
|
162
161
|
def credentials_subfolder(self) -> str:
|
|
@@ -34,14 +34,13 @@ class DictionaryType(BaseType):
|
|
|
34
34
|
def encode(self) -> Optional[str]:
|
|
35
35
|
return self.element_type.encode if hasattr(self.element_type, "encode") else None # type: ignore
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
def serialization_type(self) -> str:
|
|
37
|
+
def serialization_type(self, **kwargs: Any) -> str:
|
|
39
38
|
"""Returns the serialization value for msrest.
|
|
40
39
|
|
|
41
40
|
:return: The serialization value for msrest
|
|
42
41
|
:rtype: str
|
|
43
42
|
"""
|
|
44
|
-
return f"{{{self.element_type.serialization_type}}}"
|
|
43
|
+
return f"{{{self.element_type.serialization_type(**kwargs)}}}"
|
|
45
44
|
|
|
46
45
|
def type_annotation(self, **kwargs: Any) -> str:
|
|
47
46
|
"""The python type used for type annotation
|