@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.
- package/dist/emitter/emitter.d.ts.map +1 -1
- package/dist/emitter/emitter.js +85 -24
- 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/run-python3.d.ts +2 -0
- package/dist/emitter/run-python3.d.ts.map +1 -0
- package/dist/emitter/run-python3.js +19 -0
- package/dist/emitter/run-python3.js.map +1 -0
- package/dist/emitter/system-requirements.d.ts +17 -0
- package/dist/emitter/system-requirements.d.ts.map +1 -0
- package/dist/emitter/system-requirements.js +167 -0
- package/dist/emitter/system-requirements.js.map +1 -0
- package/emitter/src/emitter.ts +88 -23
- package/emitter/src/lib.ts +2 -0
- package/emitter/src/run-python3.ts +20 -0
- package/emitter/src/system-requirements.ts +261 -0
- package/emitter/temp/tsconfig.tsbuildinfo +1 -1
- package/eng/scripts/ci/regenerate.ts +16 -4
- package/eng/scripts/setup/__pycache__/venvtools.cpython-38.pyc +0 -0
- package/eng/scripts/setup/build.ts +16 -0
- package/eng/scripts/setup/build_pygen_wheel.py +40 -0
- package/eng/scripts/setup/install.py +9 -3
- package/eng/scripts/setup/install.ts +32 -0
- package/eng/scripts/setup/prepare.py +3 -1
- package/eng/scripts/setup/prepare.ts +11 -0
- package/eng/scripts/setup/run-python3.ts +1 -6
- package/generator/build/lib/pygen/__init__.py +107 -0
- package/generator/build/lib/pygen/_version.py +7 -0
- package/generator/build/lib/pygen/black.py +71 -0
- package/generator/build/lib/pygen/codegen/__init__.py +357 -0
- package/generator/build/lib/pygen/codegen/_utils.py +17 -0
- package/generator/build/lib/pygen/codegen/models/__init__.py +204 -0
- package/generator/build/lib/pygen/codegen/models/base.py +186 -0
- package/generator/build/lib/pygen/codegen/models/base_builder.py +118 -0
- package/generator/build/lib/pygen/codegen/models/client.py +435 -0
- package/generator/build/lib/pygen/codegen/models/code_model.py +237 -0
- package/generator/build/lib/pygen/codegen/models/combined_type.py +149 -0
- package/generator/build/lib/pygen/codegen/models/constant_type.py +129 -0
- package/generator/build/lib/pygen/codegen/models/credential_types.py +214 -0
- package/generator/build/lib/pygen/codegen/models/dictionary_type.py +127 -0
- package/generator/build/lib/pygen/codegen/models/enum_type.py +238 -0
- package/generator/build/lib/pygen/codegen/models/imports.py +291 -0
- package/generator/build/lib/pygen/codegen/models/list_type.py +143 -0
- package/generator/build/lib/pygen/codegen/models/lro_operation.py +142 -0
- package/generator/build/lib/pygen/codegen/models/lro_paging_operation.py +32 -0
- package/generator/build/lib/pygen/codegen/models/model_type.py +357 -0
- package/generator/build/lib/pygen/codegen/models/operation.py +509 -0
- package/generator/build/lib/pygen/codegen/models/operation_group.py +184 -0
- package/generator/build/lib/pygen/codegen/models/paging_operation.py +155 -0
- package/generator/build/lib/pygen/codegen/models/parameter.py +412 -0
- package/generator/build/lib/pygen/codegen/models/parameter_list.py +387 -0
- package/generator/build/lib/pygen/codegen/models/primitive_types.py +659 -0
- package/generator/build/lib/pygen/codegen/models/property.py +170 -0
- package/generator/build/lib/pygen/codegen/models/request_builder.py +189 -0
- package/generator/build/lib/pygen/codegen/models/request_builder_parameter.py +115 -0
- package/generator/build/lib/pygen/codegen/models/response.py +348 -0
- package/generator/build/lib/pygen/codegen/models/utils.py +21 -0
- package/generator/build/lib/pygen/codegen/serializers/__init__.py +574 -0
- package/generator/build/lib/pygen/codegen/serializers/base_serializer.py +21 -0
- package/generator/build/lib/pygen/codegen/serializers/builder_serializer.py +1533 -0
- package/generator/build/lib/pygen/codegen/serializers/client_serializer.py +294 -0
- package/generator/build/lib/pygen/codegen/serializers/enum_serializer.py +15 -0
- package/generator/build/lib/pygen/codegen/serializers/general_serializer.py +213 -0
- package/generator/build/lib/pygen/codegen/serializers/import_serializer.py +126 -0
- package/generator/build/lib/pygen/codegen/serializers/metadata_serializer.py +198 -0
- package/generator/build/lib/pygen/codegen/serializers/model_init_serializer.py +33 -0
- package/generator/build/lib/pygen/codegen/serializers/model_serializer.py +335 -0
- package/generator/build/lib/pygen/codegen/serializers/operation_groups_serializer.py +89 -0
- package/generator/build/lib/pygen/codegen/serializers/operations_init_serializer.py +44 -0
- package/generator/build/lib/pygen/codegen/serializers/parameter_serializer.py +221 -0
- package/generator/build/lib/pygen/codegen/serializers/patch_serializer.py +19 -0
- package/generator/build/lib/pygen/codegen/serializers/request_builders_serializer.py +52 -0
- package/generator/build/lib/pygen/codegen/serializers/sample_serializer.py +168 -0
- package/generator/build/lib/pygen/codegen/serializers/test_serializer.py +292 -0
- package/generator/build/lib/pygen/codegen/serializers/types_serializer.py +31 -0
- package/generator/build/lib/pygen/codegen/serializers/utils.py +68 -0
- package/generator/build/lib/pygen/codegen/templates/client.py.jinja2 +37 -0
- package/generator/build/lib/pygen/codegen/templates/client_container.py.jinja2 +12 -0
- package/generator/build/lib/pygen/codegen/templates/config.py.jinja2 +73 -0
- package/generator/build/lib/pygen/codegen/templates/config_container.py.jinja2 +16 -0
- package/generator/build/lib/pygen/codegen/templates/conftest.py.jinja2 +28 -0
- package/generator/build/lib/pygen/codegen/templates/enum.py.jinja2 +13 -0
- package/generator/build/lib/pygen/codegen/templates/enum_container.py.jinja2 +10 -0
- package/generator/build/lib/pygen/codegen/templates/init.py.jinja2 +24 -0
- package/generator/build/lib/pygen/codegen/templates/keywords.jinja2 +27 -0
- package/generator/build/lib/pygen/codegen/templates/lro_operation.py.jinja2 +16 -0
- package/generator/build/lib/pygen/codegen/templates/lro_paging_operation.py.jinja2 +18 -0
- package/generator/build/lib/pygen/codegen/templates/macros.jinja2 +12 -0
- package/generator/build/lib/pygen/codegen/templates/metadata.json.jinja2 +167 -0
- package/generator/build/lib/pygen/codegen/templates/model_base.py.jinja2 +1174 -0
- package/generator/build/lib/pygen/codegen/templates/model_container.py.jinja2 +15 -0
- package/generator/build/lib/pygen/codegen/templates/model_dpg.py.jinja2 +97 -0
- package/generator/build/lib/pygen/codegen/templates/model_init.py.jinja2 +33 -0
- package/generator/build/lib/pygen/codegen/templates/model_msrest.py.jinja2 +92 -0
- package/generator/build/lib/pygen/codegen/templates/operation.py.jinja2 +21 -0
- package/generator/build/lib/pygen/codegen/templates/operation_group.py.jinja2 +75 -0
- package/generator/build/lib/pygen/codegen/templates/operation_groups_container.py.jinja2 +19 -0
- package/generator/build/lib/pygen/codegen/templates/operation_tools.jinja2 +81 -0
- package/generator/build/lib/pygen/codegen/templates/operations_folder_init.py.jinja2 +17 -0
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/CHANGELOG.md.jinja2 +6 -0
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/LICENSE.jinja2 +21 -0
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/MANIFEST.in.jinja2 +8 -0
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/README.md.jinja2 +107 -0
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/dev_requirements.txt.jinja2 +9 -0
- package/generator/build/lib/pygen/codegen/templates/packaging_templates/setup.py.jinja2 +108 -0
- package/generator/build/lib/pygen/codegen/templates/paging_operation.py.jinja2 +21 -0
- package/generator/build/lib/pygen/codegen/templates/patch.py.jinja2 +19 -0
- package/generator/build/lib/pygen/codegen/templates/pkgutil_init.py.jinja2 +1 -0
- package/generator/build/lib/pygen/codegen/templates/request_builder.py.jinja2 +28 -0
- package/generator/build/lib/pygen/codegen/templates/request_builders.py.jinja2 +10 -0
- package/generator/build/lib/pygen/codegen/templates/rest_init.py.jinja2 +12 -0
- package/generator/build/lib/pygen/codegen/templates/sample.py.jinja2 +44 -0
- package/generator/build/lib/pygen/codegen/templates/serialization.py.jinja2 +2117 -0
- package/generator/build/lib/pygen/codegen/templates/test.py.jinja2 +50 -0
- package/generator/build/lib/pygen/codegen/templates/testpreparer.py.jinja2 +26 -0
- package/generator/build/lib/pygen/codegen/templates/types.py.jinja2 +7 -0
- package/generator/build/lib/pygen/codegen/templates/validation.py.jinja2 +38 -0
- package/generator/build/lib/pygen/codegen/templates/vendor.py.jinja2 +96 -0
- package/generator/build/lib/pygen/codegen/templates/version.py.jinja2 +4 -0
- package/generator/build/lib/pygen/m2r.py +65 -0
- package/generator/build/lib/pygen/preprocess/__init__.py +515 -0
- package/generator/build/lib/pygen/preprocess/helpers.py +27 -0
- package/generator/build/lib/pygen/preprocess/python_mappings.py +226 -0
- package/generator/build/lib/pygen/utils.py +163 -0
- package/generator/component-detection-pip-report.json +134 -0
- package/generator/dev_requirements.txt +0 -1
- package/generator/dist/pygen-0.1.0-py3-none-any.whl +0 -0
- package/generator/pygen.egg-info/PKG-INFO +7 -4
- package/generator/pygen.egg-info/requires.txt +7 -4
- package/generator/requirements.txt +5 -10
- package/generator/setup.py +7 -4
- package/generator/test/azure/requirements.txt +1 -1
- package/generator/test/unbranded/requirements.txt +1 -1
- package/package.json +6 -5
|
@@ -0,0 +1,142 @@
|
|
|
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, Optional, List, TYPE_CHECKING, TypeVar, Union
|
|
7
|
+
from .imports import FileImport
|
|
8
|
+
from .operation import OperationBase, Operation
|
|
9
|
+
from .response import LROPagingResponse, LROResponse, Response
|
|
10
|
+
from .imports import ImportType, TypingSection
|
|
11
|
+
from .request_builder import RequestBuilder
|
|
12
|
+
from .parameter_list import ParameterList
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from .code_model import CodeModel
|
|
16
|
+
from .client import Client
|
|
17
|
+
from . import OperationType
|
|
18
|
+
|
|
19
|
+
LROResponseType = TypeVar("LROResponseType", bound=Union[LROResponse, LROPagingResponse])
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class LROOperationBase(OperationBase[LROResponseType]):
|
|
23
|
+
def __init__(
|
|
24
|
+
self,
|
|
25
|
+
yaml_data: Dict[str, Any],
|
|
26
|
+
code_model: "CodeModel",
|
|
27
|
+
client: "Client",
|
|
28
|
+
name: str,
|
|
29
|
+
request_builder: RequestBuilder,
|
|
30
|
+
parameters: ParameterList,
|
|
31
|
+
responses: List[LROResponseType],
|
|
32
|
+
exceptions: List[Response],
|
|
33
|
+
*,
|
|
34
|
+
overloads: Optional[List[Operation]] = None,
|
|
35
|
+
) -> None:
|
|
36
|
+
super().__init__(
|
|
37
|
+
code_model=code_model,
|
|
38
|
+
client=client,
|
|
39
|
+
yaml_data=yaml_data,
|
|
40
|
+
name=name,
|
|
41
|
+
request_builder=request_builder,
|
|
42
|
+
parameters=parameters,
|
|
43
|
+
responses=responses,
|
|
44
|
+
exceptions=exceptions,
|
|
45
|
+
overloads=overloads,
|
|
46
|
+
)
|
|
47
|
+
if not self.name.lstrip("_").startswith("begin"):
|
|
48
|
+
self.name = ("_begin" if self.internal else "begin_") + self.name
|
|
49
|
+
self.lro_options: Dict[str, Any] = self.yaml_data.get("lroOptions", {})
|
|
50
|
+
self._initial_operation: Optional["OperationType"] = None
|
|
51
|
+
|
|
52
|
+
@property
|
|
53
|
+
def initial_operation(self) -> "OperationType":
|
|
54
|
+
if not self._initial_operation:
|
|
55
|
+
raise ValueError("You need to first call client.link_lro_initial_operations before accessing")
|
|
56
|
+
return self._initial_operation
|
|
57
|
+
|
|
58
|
+
@initial_operation.setter
|
|
59
|
+
def initial_operation(self, val: "OperationType") -> None:
|
|
60
|
+
self._initial_operation = val
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def operation_type(self) -> str:
|
|
64
|
+
return "lro"
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def has_optional_return_type(self) -> bool:
|
|
68
|
+
return False
|
|
69
|
+
|
|
70
|
+
@property
|
|
71
|
+
def lro_response(self) -> Optional[LROResponseType]:
|
|
72
|
+
responses_with_bodies = [r for r in self.responses if r.type]
|
|
73
|
+
num_response_schemas = {id(r.type.yaml_data) for r in responses_with_bodies if r.type}
|
|
74
|
+
response = None
|
|
75
|
+
if len(num_response_schemas) > 1:
|
|
76
|
+
# choose the response that has a status code of 200
|
|
77
|
+
try:
|
|
78
|
+
response = next(r for r in responses_with_bodies if 200 in r.status_codes)
|
|
79
|
+
except StopIteration as exc:
|
|
80
|
+
raise ValueError(
|
|
81
|
+
"Your swagger is invalid because you have multiple response schemas for LRO"
|
|
82
|
+
+ f" method {self.name} and none of them have a 200 status code."
|
|
83
|
+
) from exc
|
|
84
|
+
|
|
85
|
+
elif num_response_schemas:
|
|
86
|
+
response = responses_with_bodies[0]
|
|
87
|
+
return response
|
|
88
|
+
|
|
89
|
+
def response_type_annotation(self, **kwargs) -> str:
|
|
90
|
+
lro_response = self.lro_response or next(iter(self.responses), None)
|
|
91
|
+
if lro_response:
|
|
92
|
+
return lro_response.type_annotation(**kwargs)
|
|
93
|
+
return "None"
|
|
94
|
+
|
|
95
|
+
def cls_type_annotation(self, *, async_mode: bool) -> str:
|
|
96
|
+
"""We don't want the poller to show up in ClsType, so we call super() on response type annotation"""
|
|
97
|
+
return f"ClsType[{Response.type_annotation(self.responses[0], async_mode=async_mode)}]"
|
|
98
|
+
|
|
99
|
+
def get_poller_with_response_type(self, async_mode: bool) -> str:
|
|
100
|
+
return self.response_type_annotation(async_mode=async_mode)
|
|
101
|
+
|
|
102
|
+
def get_poller(self, async_mode: bool) -> str:
|
|
103
|
+
return self.responses[0].get_poller(async_mode)
|
|
104
|
+
|
|
105
|
+
def get_polling_method(self, async_mode: bool) -> str:
|
|
106
|
+
return self.responses[0].get_polling_method(async_mode)
|
|
107
|
+
|
|
108
|
+
def get_base_polling_method(self, async_mode: bool) -> str:
|
|
109
|
+
return self.responses[0].get_base_polling_method(async_mode)
|
|
110
|
+
|
|
111
|
+
def get_base_polling_method_path(self, async_mode: bool) -> str:
|
|
112
|
+
return self.responses[0].get_base_polling_method_path(async_mode)
|
|
113
|
+
|
|
114
|
+
def get_no_polling_method(self, async_mode: bool) -> str:
|
|
115
|
+
return self.responses[0].get_no_polling_method(async_mode)
|
|
116
|
+
|
|
117
|
+
def imports(self, async_mode: bool, **kwargs: Any) -> FileImport:
|
|
118
|
+
file_import = super().imports(async_mode, **kwargs)
|
|
119
|
+
if self.abstract:
|
|
120
|
+
return file_import
|
|
121
|
+
if async_mode and self.code_model.options["tracing"] and self.want_tracing:
|
|
122
|
+
file_import.add_submodule_import(
|
|
123
|
+
"azure.core.tracing.decorator_async",
|
|
124
|
+
"distributed_trace_async",
|
|
125
|
+
ImportType.SDKCORE,
|
|
126
|
+
)
|
|
127
|
+
if (
|
|
128
|
+
self.code_model.options["models_mode"] == "dpg"
|
|
129
|
+
and self.lro_response
|
|
130
|
+
and self.lro_response.type
|
|
131
|
+
and self.lro_response.type.type == "model"
|
|
132
|
+
):
|
|
133
|
+
# used in the case if initial operation returns none
|
|
134
|
+
# but final call returns a model
|
|
135
|
+
relative_path = "..." if async_mode else ".."
|
|
136
|
+
file_import.add_submodule_import(f"{relative_path}_model_base", "_deserialize", ImportType.LOCAL)
|
|
137
|
+
file_import.add_submodule_import("typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
138
|
+
file_import.add_submodule_import("typing", "cast", ImportType.STDLIB)
|
|
139
|
+
return file_import
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class LROOperation(LROOperationBase[LROResponse]): ...
|
|
@@ -0,0 +1,32 @@
|
|
|
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, List, Union
|
|
7
|
+
from .imports import FileImport
|
|
8
|
+
from .lro_operation import LROOperationBase
|
|
9
|
+
from .paging_operation import PagingOperationBase
|
|
10
|
+
from .response import LROPagingResponse, Response
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class LROPagingOperation(LROOperationBase[LROPagingResponse], PagingOperationBase[LROPagingResponse]):
|
|
14
|
+
@property
|
|
15
|
+
def success_status_codes(self) -> List[Union[int, str, List[int]]]:
|
|
16
|
+
"""The list of all successfull status code."""
|
|
17
|
+
return [200]
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def operation_type(self) -> str:
|
|
21
|
+
return "lropaging"
|
|
22
|
+
|
|
23
|
+
def cls_type_annotation(self, *, async_mode: bool) -> str:
|
|
24
|
+
return f"ClsType[{Response.type_annotation(self.responses[0], async_mode=async_mode)}]"
|
|
25
|
+
|
|
26
|
+
def imports(self, async_mode: bool, **kwargs: Any) -> FileImport:
|
|
27
|
+
lro_imports = LROOperationBase.imports(self, async_mode, **kwargs)
|
|
28
|
+
paging_imports = PagingOperationBase.imports(self, async_mode, **kwargs)
|
|
29
|
+
|
|
30
|
+
file_import = lro_imports
|
|
31
|
+
file_import.merge(paging_imports)
|
|
32
|
+
return file_import
|
|
@@ -0,0 +1,357 @@
|
|
|
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 enum import Enum
|
|
7
|
+
from collections import OrderedDict
|
|
8
|
+
from typing import Any, Dict, List, Optional, TYPE_CHECKING, cast
|
|
9
|
+
import sys
|
|
10
|
+
from .utils import add_to_pylint_disable
|
|
11
|
+
from .base import BaseType
|
|
12
|
+
from .constant_type import ConstantType
|
|
13
|
+
from .property import Property
|
|
14
|
+
from .imports import FileImport, ImportType, TypingSection
|
|
15
|
+
from ...utils import NAME_LENGTH_LIMIT
|
|
16
|
+
|
|
17
|
+
if sys.version_info >= (3, 8):
|
|
18
|
+
from typing import Literal
|
|
19
|
+
else:
|
|
20
|
+
from typing_extensions import Literal # type: ignore
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from .code_model import CodeModel
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class UsageFlags(Enum):
|
|
27
|
+
Default = 0
|
|
28
|
+
Input = 2
|
|
29
|
+
Output = 4
|
|
30
|
+
ApiVersionEnum = 8
|
|
31
|
+
JsonMergePatch = 16
|
|
32
|
+
MultipartFormData = 32
|
|
33
|
+
Spread = 64
|
|
34
|
+
Error = 128
|
|
35
|
+
Json = 256
|
|
36
|
+
Xml = 512
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _get_properties(type: "ModelType", properties: List[Property]) -> List[Property]:
|
|
40
|
+
for parent in type.parents:
|
|
41
|
+
# here we're adding the properties from our parents
|
|
42
|
+
|
|
43
|
+
# need to make sure that the properties we choose from our parent also don't contain
|
|
44
|
+
# any of our own properties
|
|
45
|
+
property_names = set([p.client_name for p in properties] + [p.client_name for p in type.properties])
|
|
46
|
+
chosen_parent_properties = [p for p in parent.properties if p.client_name not in property_names]
|
|
47
|
+
properties = _get_properties(parent, chosen_parent_properties) + properties
|
|
48
|
+
return properties
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class ModelType(BaseType): # pylint: disable=too-many-instance-attributes, too-many-public-methods
|
|
52
|
+
"""Represents a class ready to be serialized in Python.
|
|
53
|
+
|
|
54
|
+
:param str name: The name of the class.
|
|
55
|
+
:param str description: The description of the class.
|
|
56
|
+
:param properties: the optional properties of the class.
|
|
57
|
+
:type properties: dict(str, str)
|
|
58
|
+
"""
|
|
59
|
+
|
|
60
|
+
base: Literal["msrest", "dpg", "json"]
|
|
61
|
+
|
|
62
|
+
def __init__(
|
|
63
|
+
self,
|
|
64
|
+
yaml_data: Dict[str, Any],
|
|
65
|
+
code_model: "CodeModel",
|
|
66
|
+
*,
|
|
67
|
+
properties: Optional[List[Property]] = None,
|
|
68
|
+
parents: Optional[List["ModelType"]] = None,
|
|
69
|
+
discriminated_subtypes: Optional[Dict[str, "ModelType"]] = None,
|
|
70
|
+
) -> None:
|
|
71
|
+
super().__init__(yaml_data=yaml_data, code_model=code_model)
|
|
72
|
+
self.name: str = self.yaml_data["name"]
|
|
73
|
+
self.max_properties: Optional[int] = self.yaml_data.get("maxProperties")
|
|
74
|
+
self.min_properties: Optional[int] = self.yaml_data.get("minProperties")
|
|
75
|
+
self.properties = properties or []
|
|
76
|
+
self.parents = parents or []
|
|
77
|
+
self.discriminated_subtypes = discriminated_subtypes or {}
|
|
78
|
+
self.discriminator_value: Optional[str] = self.yaml_data.get("discriminatorValue")
|
|
79
|
+
self._created_json_template_representation = False
|
|
80
|
+
self._got_polymorphic_subtypes = False
|
|
81
|
+
self.internal: bool = self.yaml_data.get("internal", False)
|
|
82
|
+
self.snake_case_name: str = self.yaml_data["snakeCaseName"]
|
|
83
|
+
self.cross_language_definition_id: Optional[str] = self.yaml_data.get("crossLanguageDefinitionId")
|
|
84
|
+
self.usage: int = self.yaml_data.get("usage", UsageFlags.Input.value | UsageFlags.Output.value)
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def is_usage_output(self) -> bool:
|
|
88
|
+
return bool(self.usage & UsageFlags.Output.value)
|
|
89
|
+
|
|
90
|
+
@property
|
|
91
|
+
def flattened_property(self) -> Optional[Property]:
|
|
92
|
+
try:
|
|
93
|
+
return next(p for p in self.properties if p.flatten)
|
|
94
|
+
except StopIteration:
|
|
95
|
+
return None
|
|
96
|
+
|
|
97
|
+
@property
|
|
98
|
+
def flattened_items(self) -> List[str]:
|
|
99
|
+
return [
|
|
100
|
+
item.client_name
|
|
101
|
+
for prop in self.properties
|
|
102
|
+
if isinstance(prop.type, ModelType) and prop.flatten
|
|
103
|
+
for item in prop.type.properties
|
|
104
|
+
]
|
|
105
|
+
|
|
106
|
+
@property
|
|
107
|
+
def is_form_data(self) -> bool:
|
|
108
|
+
return any(p.is_multipart_file_input for p in self.properties)
|
|
109
|
+
|
|
110
|
+
@property
|
|
111
|
+
def is_xml(self) -> bool:
|
|
112
|
+
return self.yaml_data.get("isXml", False)
|
|
113
|
+
|
|
114
|
+
@property
|
|
115
|
+
def msrest_deserialization_key(self) -> str:
|
|
116
|
+
return self.name
|
|
117
|
+
|
|
118
|
+
@property
|
|
119
|
+
def is_polymorphic(self) -> bool:
|
|
120
|
+
return any(p.is_polymorphic for p in self.properties)
|
|
121
|
+
|
|
122
|
+
def description(self, *, is_operation_file: bool = False) -> str:
|
|
123
|
+
return "" if is_operation_file else self.yaml_data.get("description", self.name)
|
|
124
|
+
|
|
125
|
+
def get_declaration(self, value: Any) -> str:
|
|
126
|
+
return f"{self.name}()"
|
|
127
|
+
|
|
128
|
+
def __repr__(self) -> str:
|
|
129
|
+
return f"<{self.__class__.__name__} {self.name}>"
|
|
130
|
+
|
|
131
|
+
@property
|
|
132
|
+
def xml_serialization_ctxt(self) -> Optional[str]:
|
|
133
|
+
# object schema contains _xml_map, they don't need serialization context
|
|
134
|
+
return ""
|
|
135
|
+
|
|
136
|
+
@property
|
|
137
|
+
def xml_map_content(self) -> Optional[str]:
|
|
138
|
+
# This is NOT an error on the super call, we use the serialization context for "xml_map",
|
|
139
|
+
# but we don't want to write a serialization context for an object.
|
|
140
|
+
return super().xml_serialization_ctxt
|
|
141
|
+
|
|
142
|
+
@property
|
|
143
|
+
def discriminated_subtypes_name_mapping(self) -> Dict[str, str]:
|
|
144
|
+
return {k: v.name for k, v in self.discriminated_subtypes.items()}
|
|
145
|
+
|
|
146
|
+
def get_json_template_representation(
|
|
147
|
+
self,
|
|
148
|
+
*,
|
|
149
|
+
client_default_value_declaration: Optional[str] = None,
|
|
150
|
+
) -> Any:
|
|
151
|
+
if self._created_json_template_representation:
|
|
152
|
+
return "..." # do this to avoid loop
|
|
153
|
+
self._created_json_template_representation = True
|
|
154
|
+
if self.discriminated_subtypes:
|
|
155
|
+
# we will instead print the discriminated subtypes
|
|
156
|
+
self._created_json_template_representation = False
|
|
157
|
+
return f'"{self.snake_case_name}"' if self.code_model.for_test else self.snake_case_name
|
|
158
|
+
|
|
159
|
+
# don't add additional properties, because there's not really a concept of
|
|
160
|
+
# additional properties in the template
|
|
161
|
+
representation = {
|
|
162
|
+
f'"{prop.wire_name}"': prop.get_json_template_representation(
|
|
163
|
+
client_default_value_declaration=client_default_value_declaration,
|
|
164
|
+
)
|
|
165
|
+
for prop in [
|
|
166
|
+
p for p in self.properties if not (p.is_discriminator or p.client_name == "additional_properties")
|
|
167
|
+
]
|
|
168
|
+
}
|
|
169
|
+
if self.discriminator and self.discriminator_value:
|
|
170
|
+
representation[f'"{self.discriminator.wire_name}"'] = f'"{self.discriminator_value}"'
|
|
171
|
+
|
|
172
|
+
# once we've finished, we want to reset created_json_template_representation to false
|
|
173
|
+
# so we can call it again
|
|
174
|
+
self._created_json_template_representation = False
|
|
175
|
+
optional_keys = [f'"{p.wire_name}"' for p in self.properties if getattr(p, "optional", False)]
|
|
176
|
+
return OrderedDict(
|
|
177
|
+
sorted(
|
|
178
|
+
representation.items(),
|
|
179
|
+
key=lambda item: f"{1 if item[0] in optional_keys else 0}{item[0]}",
|
|
180
|
+
)
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
def get_polymorphic_subtypes(self, polymorphic_subtypes: List["ModelType"]) -> None:
|
|
184
|
+
is_polymorphic_subtype = self.discriminator_value and not self.discriminated_subtypes
|
|
185
|
+
if self._got_polymorphic_subtypes:
|
|
186
|
+
return
|
|
187
|
+
self._got_polymorphic_subtypes = True
|
|
188
|
+
if self.name not in (m.name for m in polymorphic_subtypes) and is_polymorphic_subtype:
|
|
189
|
+
polymorphic_subtypes.append(self)
|
|
190
|
+
for discriminated_subtype in self.discriminated_subtypes.values():
|
|
191
|
+
discriminated_subtype.get_polymorphic_subtypes(polymorphic_subtypes)
|
|
192
|
+
for property in self.properties:
|
|
193
|
+
property.get_polymorphic_subtypes(polymorphic_subtypes)
|
|
194
|
+
self._got_polymorphic_subtypes = False
|
|
195
|
+
|
|
196
|
+
@classmethod
|
|
197
|
+
def from_yaml(cls, yaml_data: Dict[str, Any], code_model: "CodeModel") -> "ModelType":
|
|
198
|
+
raise ValueError(
|
|
199
|
+
"You shouldn't call from_yaml for ModelType to avoid recursion. "
|
|
200
|
+
"Please initial a blank ModelType, then call .fill_instance_from_yaml on the created type."
|
|
201
|
+
)
|
|
202
|
+
|
|
203
|
+
def fill_instance_from_yaml(self, yaml_data: Dict[str, Any], code_model: "CodeModel") -> None:
|
|
204
|
+
from . import build_type
|
|
205
|
+
|
|
206
|
+
self.parents = [cast(ModelType, build_type(bm, code_model)) for bm in yaml_data.get("parents", [])]
|
|
207
|
+
properties = [Property.from_yaml(p, code_model) for p in yaml_data["properties"]]
|
|
208
|
+
self.properties = _get_properties(self, properties)
|
|
209
|
+
# checking to see if this is a polymorphic class
|
|
210
|
+
self.discriminated_subtypes = {
|
|
211
|
+
k: cast(ModelType, build_type(v, code_model))
|
|
212
|
+
for k, v in self.yaml_data.get("discriminatedSubtypes", {}).items()
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
@property
|
|
216
|
+
def has_readonly_or_constant_property(self) -> bool:
|
|
217
|
+
return any(x.readonly or x.constant or x.visibility == ["read"] for x in self.properties)
|
|
218
|
+
|
|
219
|
+
@property
|
|
220
|
+
def discriminator(self) -> Optional[Property]:
|
|
221
|
+
try:
|
|
222
|
+
return next(p for p in self.properties if p.is_discriminator)
|
|
223
|
+
except StopIteration:
|
|
224
|
+
return None
|
|
225
|
+
|
|
226
|
+
@property
|
|
227
|
+
def discriminator_property(self) -> Optional[Property]:
|
|
228
|
+
try:
|
|
229
|
+
return next(
|
|
230
|
+
p
|
|
231
|
+
for p in self.properties
|
|
232
|
+
if p.is_discriminator and isinstance(p.type, ConstantType) and p.type.value == self.discriminator_value
|
|
233
|
+
)
|
|
234
|
+
except StopIteration:
|
|
235
|
+
return None
|
|
236
|
+
|
|
237
|
+
def pylint_disable(self) -> str:
|
|
238
|
+
retval: str = ""
|
|
239
|
+
if len(self.name) > NAME_LENGTH_LIMIT:
|
|
240
|
+
retval = add_to_pylint_disable(retval, "name-too-long")
|
|
241
|
+
return retval
|
|
242
|
+
|
|
243
|
+
@property
|
|
244
|
+
def init_pylint_disable(self) -> str:
|
|
245
|
+
retval: str = ""
|
|
246
|
+
if len(self.properties) > 23:
|
|
247
|
+
retval = add_to_pylint_disable(retval, "too-many-locals")
|
|
248
|
+
return retval
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
class JSONModelType(ModelType):
|
|
252
|
+
base = "json"
|
|
253
|
+
|
|
254
|
+
def type_annotation(self, **kwargs: Any) -> str:
|
|
255
|
+
return "ET.Element" if self.is_xml else "JSON"
|
|
256
|
+
|
|
257
|
+
@property
|
|
258
|
+
def serialization_type(self) -> str:
|
|
259
|
+
return "object"
|
|
260
|
+
|
|
261
|
+
def docstring_type(self, **kwargs: Any) -> str:
|
|
262
|
+
return "ET.Element" if self.is_xml else "JSON"
|
|
263
|
+
|
|
264
|
+
def docstring_text(self, **kwargs: Any) -> str:
|
|
265
|
+
return "XML Element" if self.is_xml else "JSON object"
|
|
266
|
+
|
|
267
|
+
@property
|
|
268
|
+
def instance_check_template(self) -> str:
|
|
269
|
+
return "isinstance({}, MutableMapping)"
|
|
270
|
+
|
|
271
|
+
def imports(self, **kwargs: Any) -> FileImport:
|
|
272
|
+
file_import = FileImport(self.code_model)
|
|
273
|
+
file_import.add_submodule_import("typing", "Any", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
274
|
+
file_import.define_mutable_mapping_type()
|
|
275
|
+
if self.is_xml:
|
|
276
|
+
file_import.add_submodule_import("xml.etree", "ElementTree", ImportType.STDLIB, alias="ET")
|
|
277
|
+
return file_import
|
|
278
|
+
|
|
279
|
+
|
|
280
|
+
class GeneratedModelType(ModelType):
|
|
281
|
+
def type_annotation(self, **kwargs: Any) -> str:
|
|
282
|
+
is_operation_file = kwargs.pop("is_operation_file", False)
|
|
283
|
+
skip_quote = kwargs.get("skip_quote", False)
|
|
284
|
+
module_name = "_models." if kwargs.get("need_module_name", True) else ""
|
|
285
|
+
file_name = f"{self.code_model.models_filename}." if self.internal else ""
|
|
286
|
+
retval = module_name + file_name + self.name
|
|
287
|
+
return retval if is_operation_file or skip_quote else f'"{retval}"'
|
|
288
|
+
|
|
289
|
+
def docstring_type(self, **kwargs: Any) -> str:
|
|
290
|
+
return f"~{self.code_model.namespace}.models.{self.type_annotation(need_module_name=False, skip_quote=True)}"
|
|
291
|
+
|
|
292
|
+
def docstring_text(self, **kwargs: Any) -> str:
|
|
293
|
+
return self.name
|
|
294
|
+
|
|
295
|
+
@property
|
|
296
|
+
def type_description(self) -> str:
|
|
297
|
+
return self.name
|
|
298
|
+
|
|
299
|
+
def imports(self, **kwargs: Any) -> FileImport:
|
|
300
|
+
file_import = super().imports(**kwargs)
|
|
301
|
+
relative_path = kwargs.pop("relative_path", None)
|
|
302
|
+
if relative_path:
|
|
303
|
+
# add import for models in operations or _types file
|
|
304
|
+
file_import.add_submodule_import(
|
|
305
|
+
relative_path,
|
|
306
|
+
"models",
|
|
307
|
+
ImportType.LOCAL,
|
|
308
|
+
alias="_models",
|
|
309
|
+
typing_section=(TypingSection.TYPING if kwargs.get("model_typing") else TypingSection.REGULAR),
|
|
310
|
+
)
|
|
311
|
+
if self.is_form_data:
|
|
312
|
+
file_import.add_submodule_import(
|
|
313
|
+
relative_path,
|
|
314
|
+
"_model_base",
|
|
315
|
+
ImportType.LOCAL,
|
|
316
|
+
typing_section=(TypingSection.TYPING if kwargs.get("model_typing") else TypingSection.REGULAR),
|
|
317
|
+
)
|
|
318
|
+
return file_import
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
class MsrestModelType(GeneratedModelType):
|
|
322
|
+
base = "msrest"
|
|
323
|
+
|
|
324
|
+
@property
|
|
325
|
+
def serialization_type(self) -> str:
|
|
326
|
+
return self.type_annotation(skip_quote=True) if self.internal else self.name
|
|
327
|
+
|
|
328
|
+
@property
|
|
329
|
+
def instance_check_template(self) -> str:
|
|
330
|
+
return "isinstance({}, msrest.Model)"
|
|
331
|
+
|
|
332
|
+
def imports(self, **kwargs: Any) -> FileImport:
|
|
333
|
+
file_import = super().imports(**kwargs)
|
|
334
|
+
file_import.add_submodule_import("typing", "Any", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
335
|
+
return file_import
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
class DPGModelType(GeneratedModelType):
|
|
339
|
+
base = "dpg"
|
|
340
|
+
|
|
341
|
+
@property
|
|
342
|
+
def serialization_type(self) -> str:
|
|
343
|
+
return (
|
|
344
|
+
self.type_annotation(skip_quote=True)
|
|
345
|
+
if self.internal
|
|
346
|
+
else self.type_annotation(need_module_name=False, skip_quote=True)
|
|
347
|
+
)
|
|
348
|
+
|
|
349
|
+
@property
|
|
350
|
+
def instance_check_template(self) -> str:
|
|
351
|
+
return "isinstance({}, " + f"_models.{self.name})"
|
|
352
|
+
|
|
353
|
+
def imports(self, **kwargs: Any) -> FileImport:
|
|
354
|
+
file_import = super().imports(**kwargs)
|
|
355
|
+
if self.flattened_property:
|
|
356
|
+
file_import.add_submodule_import("typing", "Any", ImportType.STDLIB)
|
|
357
|
+
return file_import
|