@typespec/http-client-python 0.4.4 → 0.5.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/emitter.d.ts.map +1 -1
- package/dist/emitter/emitter.js +110 -24
- package/dist/emitter/emitter.js.map +1 -1
- package/dist/emitter/http.js +1 -1
- package/dist/emitter/http.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 +111 -23
- package/emitter/src/http.ts +1 -1
- 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/Test-Packages.ps1 +1 -1
- package/eng/scripts/ci/regenerate.ts +20 -8
- 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 -8
- package/eng/scripts/setup/install.ts +12 -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/codegen/__init__.py +4 -4
- package/generator/pygen.egg-info/PKG-INFO +7 -4
- package/generator/pygen.egg-info/requires.txt +7 -4
- package/generator/setup.py +7 -4
- package/generator/test/azure/mock_api_tests/asynctests/test_azure_client_generator_core_flatten_async.py +1 -1
- package/generator/test/{generic_mock_api_tests/asynctests/test_payload_pageable_async.py → azure/mock_api_tests/asynctests/test_azure_payload_pageable_async.py} +1 -1
- package/generator/test/azure/mock_api_tests/conftest.py +5 -4
- package/generator/test/azure/mock_api_tests/test_azure_client_generator_core_flatten.py +1 -1
- package/generator/test/{generic_mock_api_tests/test_payload_pageable.py → azure/mock_api_tests/test_azure_payload_pageable.py} +1 -1
- package/generator/test/{generic_mock_api_tests → azure/mock_api_tests}/test_resiliency_srv_driven.py +4 -2
- package/generator/test/{generic_mock_api_tests/asynctests → azure/mock_api_tests}/test_resiliency_srv_driven_async.py +3 -2
- package/generator/test/azure/requirements.txt +9 -8
- package/generator/test/generic_mock_api_tests/conftest.py +9 -4
- package/generator/test/unbranded/mock_api_tests/conftest.py +4 -4
- package/generator/test/unbranded/mock_api_tests/test_unbranded.py +1 -1
- package/generator/test/unbranded/requirements.txt +1 -8
- package/package.json +10 -10
- package/generator/requirements.txt +0 -12
- /package/generator/test/{generic_mock_api_tests → azure/mock_api_tests}/asynctests/test_client_naming_async.py +0 -0
- /package/generator/test/{generic_mock_api_tests → azure/mock_api_tests}/asynctests/test_client_structure_async.py +0 -0
- /package/generator/test/{generic_mock_api_tests → azure/mock_api_tests}/test_client_naming.py +0 -0
- /package/generator/test/{generic_mock_api_tests → azure/mock_api_tests}/test_client_structure.py +0 -0
|
@@ -0,0 +1,509 @@
|
|
|
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 (
|
|
7
|
+
Dict,
|
|
8
|
+
List,
|
|
9
|
+
Any,
|
|
10
|
+
Optional,
|
|
11
|
+
Union,
|
|
12
|
+
TYPE_CHECKING,
|
|
13
|
+
Generic,
|
|
14
|
+
TypeVar,
|
|
15
|
+
cast,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
from .request_builder_parameter import RequestBuilderParameter
|
|
19
|
+
|
|
20
|
+
from .utils import OrderedSet, add_to_pylint_disable
|
|
21
|
+
from .base_builder import BaseBuilder
|
|
22
|
+
from .imports import FileImport, ImportType, TypingSection
|
|
23
|
+
from .response import (
|
|
24
|
+
Response,
|
|
25
|
+
PagingResponse,
|
|
26
|
+
LROResponse,
|
|
27
|
+
LROPagingResponse,
|
|
28
|
+
get_response,
|
|
29
|
+
)
|
|
30
|
+
from .parameter import (
|
|
31
|
+
BodyParameter,
|
|
32
|
+
Parameter,
|
|
33
|
+
ParameterLocation,
|
|
34
|
+
)
|
|
35
|
+
from .parameter_list import ParameterList
|
|
36
|
+
from .model_type import ModelType
|
|
37
|
+
from .base import BaseType
|
|
38
|
+
from .request_builder import OverloadedRequestBuilder, RequestBuilder
|
|
39
|
+
from ...utils import xml_serializable, json_serializable, NAME_LENGTH_LIMIT
|
|
40
|
+
|
|
41
|
+
if TYPE_CHECKING:
|
|
42
|
+
from .code_model import CodeModel
|
|
43
|
+
from .client import Client
|
|
44
|
+
from . import OperationType
|
|
45
|
+
|
|
46
|
+
ResponseType = TypeVar(
|
|
47
|
+
"ResponseType",
|
|
48
|
+
bound=Union[Response, PagingResponse, LROResponse, LROPagingResponse],
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def is_internal(target: Optional[BaseType]) -> bool:
|
|
53
|
+
return isinstance(target, ModelType) and target.base == "dpg" and target.internal
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class OperationBase( # pylint: disable=too-many-public-methods,too-many-instance-attributes
|
|
57
|
+
Generic[ResponseType], BaseBuilder[ParameterList, List["Operation"]]
|
|
58
|
+
):
|
|
59
|
+
def __init__(
|
|
60
|
+
self,
|
|
61
|
+
yaml_data: Dict[str, Any],
|
|
62
|
+
code_model: "CodeModel",
|
|
63
|
+
client: "Client",
|
|
64
|
+
name: str,
|
|
65
|
+
request_builder: Union[RequestBuilder, OverloadedRequestBuilder],
|
|
66
|
+
parameters: ParameterList,
|
|
67
|
+
responses: List[ResponseType],
|
|
68
|
+
exceptions: List[Response],
|
|
69
|
+
*,
|
|
70
|
+
overloads: Optional[List["Operation"]] = None,
|
|
71
|
+
) -> None:
|
|
72
|
+
super().__init__(
|
|
73
|
+
code_model=code_model,
|
|
74
|
+
client=client,
|
|
75
|
+
yaml_data=yaml_data,
|
|
76
|
+
name=name,
|
|
77
|
+
parameters=parameters,
|
|
78
|
+
overloads=overloads,
|
|
79
|
+
)
|
|
80
|
+
self.overloads: List["Operation"] = overloads or []
|
|
81
|
+
self.responses = responses
|
|
82
|
+
self.request_builder = request_builder
|
|
83
|
+
self.deprecated = False
|
|
84
|
+
self.exceptions = exceptions
|
|
85
|
+
self.is_lro_initial_operation: bool = self.yaml_data.get("isLroInitialOperation", False)
|
|
86
|
+
self.include_documentation: bool = not self.is_lro_initial_operation
|
|
87
|
+
self.internal: bool = self.yaml_data.get("internal", False)
|
|
88
|
+
if self.internal and not self.name.startswith("_"):
|
|
89
|
+
self.name = "_" + self.name
|
|
90
|
+
self.has_etag: bool = self.yaml_data.get("hasEtag", False)
|
|
91
|
+
self.cross_language_definition_id: Optional[str] = self.yaml_data.get("crossLanguageDefinitionId")
|
|
92
|
+
|
|
93
|
+
@property
|
|
94
|
+
def stream_value(self) -> Union[str, bool]:
|
|
95
|
+
return (
|
|
96
|
+
f'kwargs.pop("stream", {self.has_stream_response})'
|
|
97
|
+
if self.expose_stream_keyword and self.has_response_body
|
|
98
|
+
else self.has_stream_response
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
def has_form_data_body(self):
|
|
103
|
+
return self.parameters.has_form_data_body
|
|
104
|
+
|
|
105
|
+
@property
|
|
106
|
+
def expose_stream_keyword(self) -> bool:
|
|
107
|
+
return self.yaml_data.get("exposeStreamKeyword", False)
|
|
108
|
+
|
|
109
|
+
@property
|
|
110
|
+
def operation_type(self) -> str:
|
|
111
|
+
return "operation"
|
|
112
|
+
|
|
113
|
+
@property
|
|
114
|
+
def has_optional_return_type(self) -> bool:
|
|
115
|
+
"""Has optional return type if there are multiple successful response types where some have
|
|
116
|
+
bodies and some are None
|
|
117
|
+
"""
|
|
118
|
+
# means if we have at least one successful response with a body and one without
|
|
119
|
+
successful_response_with_body = any(r for r in self.responses if r.type)
|
|
120
|
+
successful_response_without_body = any(r for r in self.responses if not r.type)
|
|
121
|
+
return successful_response_with_body and successful_response_without_body
|
|
122
|
+
|
|
123
|
+
def response_type_annotation(self, **kwargs) -> str:
|
|
124
|
+
if self.code_model.options["head_as_boolean"] and self.request_builder.method.lower() == "head":
|
|
125
|
+
return "bool"
|
|
126
|
+
response_type_annotations: OrderedSet[str] = {
|
|
127
|
+
response.type_annotation(**kwargs): None for response in self.responses if response.type
|
|
128
|
+
}
|
|
129
|
+
response_str = ", ".join(response_type_annotations.keys())
|
|
130
|
+
if len(response_type_annotations) > 1:
|
|
131
|
+
return f"Union[{response_str}]"
|
|
132
|
+
if self.has_optional_return_type:
|
|
133
|
+
return f"Optional[{response_str}]"
|
|
134
|
+
if self.responses:
|
|
135
|
+
return self.responses[0].type_annotation(**kwargs)
|
|
136
|
+
return "None"
|
|
137
|
+
|
|
138
|
+
def pylint_disable(self, async_mode: bool) -> str:
|
|
139
|
+
retval: str = ""
|
|
140
|
+
if not async_mode and not self.is_overload and self.response_type_annotation(async_mode=False) == "None":
|
|
141
|
+
# doesn't matter if it's async or not
|
|
142
|
+
retval = add_to_pylint_disable(retval, "inconsistent-return-statements")
|
|
143
|
+
if len(self.name) > NAME_LENGTH_LIMIT:
|
|
144
|
+
retval = add_to_pylint_disable(retval, "name-too-long")
|
|
145
|
+
return retval
|
|
146
|
+
|
|
147
|
+
def cls_type_annotation(self, *, async_mode: bool) -> str:
|
|
148
|
+
if self.request_builder.method.lower() == "head" and self.code_model.options["head_as_boolean"]:
|
|
149
|
+
return "ClsType[None]"
|
|
150
|
+
return f"ClsType[{self.response_type_annotation(async_mode=async_mode)}]"
|
|
151
|
+
|
|
152
|
+
def _response_docstring_helper(self, attr_name: str, **kwargs: Any) -> str:
|
|
153
|
+
responses_with_body = [r for r in self.responses if r.type]
|
|
154
|
+
if self.request_builder.method.lower() == "head" and self.code_model.options["head_as_boolean"]:
|
|
155
|
+
return "bool"
|
|
156
|
+
if responses_with_body:
|
|
157
|
+
response_docstring_values: OrderedSet[str] = {
|
|
158
|
+
getattr(response, attr_name)(**kwargs): None for response in responses_with_body
|
|
159
|
+
}
|
|
160
|
+
retval = " or ".join(response_docstring_values.keys())
|
|
161
|
+
if self.has_optional_return_type:
|
|
162
|
+
retval += " or None"
|
|
163
|
+
return retval
|
|
164
|
+
if self.responses:
|
|
165
|
+
return getattr(self.responses[0], attr_name)(**kwargs)
|
|
166
|
+
return "None"
|
|
167
|
+
|
|
168
|
+
def response_docstring_text(self, **kwargs) -> str:
|
|
169
|
+
retval = self._response_docstring_helper("docstring_text", **kwargs)
|
|
170
|
+
if not self.code_model.options["version_tolerant"]:
|
|
171
|
+
retval += " or the result of cls(response)"
|
|
172
|
+
if self.code_model.options["models_mode"] == "dpg" and any(
|
|
173
|
+
isinstance(r.type, ModelType) for r in self.responses
|
|
174
|
+
):
|
|
175
|
+
r = next(r for r in self.responses if isinstance(r.type, ModelType))
|
|
176
|
+
item_type = getattr(r, "item_type", getattr(r, "type"))
|
|
177
|
+
if item_type:
|
|
178
|
+
type_name = item_type.docstring_text(**kwargs)
|
|
179
|
+
retval += f". The {type_name} is compatible with MutableMapping"
|
|
180
|
+
return retval
|
|
181
|
+
|
|
182
|
+
def response_docstring_type(self, **kwargs) -> str:
|
|
183
|
+
return self._response_docstring_helper("docstring_type", **kwargs)
|
|
184
|
+
|
|
185
|
+
@property
|
|
186
|
+
def has_response_body(self) -> bool:
|
|
187
|
+
"""Tell if at least one response has a body."""
|
|
188
|
+
return any(response.type for response in self.responses)
|
|
189
|
+
|
|
190
|
+
@property
|
|
191
|
+
def any_response_has_headers(self) -> bool:
|
|
192
|
+
return any(response.headers for response in self.responses)
|
|
193
|
+
|
|
194
|
+
@property
|
|
195
|
+
def default_error_deserialization(self) -> Optional[str]:
|
|
196
|
+
default_exceptions = [e for e in self.exceptions if "default" in e.status_codes and e.type]
|
|
197
|
+
if not default_exceptions:
|
|
198
|
+
return None
|
|
199
|
+
exception_schema = default_exceptions[0].type
|
|
200
|
+
if isinstance(exception_schema, ModelType):
|
|
201
|
+
return exception_schema.type_annotation(skip_quote=True)
|
|
202
|
+
return None if self.code_model.options["models_mode"] == "dpg" else "'object'"
|
|
203
|
+
|
|
204
|
+
@property
|
|
205
|
+
def non_default_errors(self) -> List[Response]:
|
|
206
|
+
return [
|
|
207
|
+
e for e in self.exceptions if "default" not in e.status_codes and e.type and isinstance(e.type, ModelType)
|
|
208
|
+
]
|
|
209
|
+
|
|
210
|
+
def _imports_shared(self, async_mode: bool, **kwargs: Any) -> FileImport: # pylint: disable=unused-argument
|
|
211
|
+
file_import = FileImport(self.code_model)
|
|
212
|
+
file_import.add_submodule_import("typing", "Any", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
213
|
+
|
|
214
|
+
response_types = [r.type_annotation(async_mode=async_mode, operation=self) for r in self.responses if r.type]
|
|
215
|
+
if len(set(response_types)) > 1:
|
|
216
|
+
file_import.add_submodule_import("typing", "Union", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
217
|
+
if self.added_on:
|
|
218
|
+
file_import.add_submodule_import(
|
|
219
|
+
f"{'.' if async_mode else ''}.._validation",
|
|
220
|
+
"api_version_validation",
|
|
221
|
+
ImportType.LOCAL,
|
|
222
|
+
)
|
|
223
|
+
return file_import
|
|
224
|
+
|
|
225
|
+
def imports_for_multiapi(self, async_mode: bool, **kwargs: Any) -> FileImport:
|
|
226
|
+
if self.abstract:
|
|
227
|
+
return FileImport(self.code_model)
|
|
228
|
+
file_import = self._imports_shared(async_mode, **kwargs)
|
|
229
|
+
for param in self.parameters.method:
|
|
230
|
+
file_import.merge(
|
|
231
|
+
param.imports_for_multiapi(
|
|
232
|
+
async_mode,
|
|
233
|
+
operation=self,
|
|
234
|
+
**kwargs,
|
|
235
|
+
)
|
|
236
|
+
)
|
|
237
|
+
for response in self.responses:
|
|
238
|
+
file_import.merge(response.imports_for_multiapi(async_mode=async_mode, operation=self, **kwargs))
|
|
239
|
+
if self.code_model.options["models_mode"]:
|
|
240
|
+
for exception in self.exceptions:
|
|
241
|
+
file_import.merge(exception.imports_for_multiapi(async_mode=async_mode, operation=self, **kwargs))
|
|
242
|
+
return file_import
|
|
243
|
+
|
|
244
|
+
@staticmethod
|
|
245
|
+
def has_kwargs_to_pop_with_default(
|
|
246
|
+
kwargs_to_pop: List[
|
|
247
|
+
Union[
|
|
248
|
+
Parameter,
|
|
249
|
+
RequestBuilderParameter,
|
|
250
|
+
BodyParameter,
|
|
251
|
+
]
|
|
252
|
+
],
|
|
253
|
+
location: ParameterLocation,
|
|
254
|
+
) -> bool:
|
|
255
|
+
return any(
|
|
256
|
+
(kwarg.client_default_value or kwarg.optional) and kwarg.location == location for kwarg in kwargs_to_pop
|
|
257
|
+
)
|
|
258
|
+
|
|
259
|
+
@property
|
|
260
|
+
def need_validation(self) -> bool:
|
|
261
|
+
"""Whether we need parameter / operation validation. For API version."""
|
|
262
|
+
return bool(self.added_on) or any(p for p in self.parameters if p.added_on)
|
|
263
|
+
|
|
264
|
+
def get_request_builder_import(
|
|
265
|
+
self,
|
|
266
|
+
request_builder: Union[RequestBuilder, OverloadedRequestBuilder],
|
|
267
|
+
async_mode: bool,
|
|
268
|
+
) -> FileImport:
|
|
269
|
+
"""Helper method to get a request builder import."""
|
|
270
|
+
file_import = FileImport(self.code_model)
|
|
271
|
+
if self.code_model.options["builders_visibility"] != "embedded":
|
|
272
|
+
group_name = request_builder.group_name
|
|
273
|
+
rest_import_path = "..." if async_mode else ".."
|
|
274
|
+
if group_name:
|
|
275
|
+
file_import.add_submodule_import(
|
|
276
|
+
f"{rest_import_path}{self.code_model.rest_layer_name}",
|
|
277
|
+
group_name,
|
|
278
|
+
import_type=ImportType.LOCAL,
|
|
279
|
+
alias=f"rest_{group_name}",
|
|
280
|
+
)
|
|
281
|
+
else:
|
|
282
|
+
file_import.add_submodule_import(
|
|
283
|
+
rest_import_path,
|
|
284
|
+
self.code_model.rest_layer_name,
|
|
285
|
+
import_type=ImportType.LOCAL,
|
|
286
|
+
alias="rest",
|
|
287
|
+
)
|
|
288
|
+
if self.code_model.options["builders_visibility"] == "embedded" and async_mode:
|
|
289
|
+
file_import.add_submodule_import(
|
|
290
|
+
f"...{self.code_model.operations_folder_name}.{self.filename}",
|
|
291
|
+
request_builder.name,
|
|
292
|
+
import_type=ImportType.LOCAL,
|
|
293
|
+
)
|
|
294
|
+
return file_import
|
|
295
|
+
|
|
296
|
+
def imports( # pylint: disable=too-many-branches, disable=too-many-statements
|
|
297
|
+
self, async_mode: bool, **kwargs: Any
|
|
298
|
+
) -> FileImport:
|
|
299
|
+
if self.abstract:
|
|
300
|
+
return FileImport(self.code_model)
|
|
301
|
+
file_import = self._imports_shared(async_mode, **kwargs)
|
|
302
|
+
|
|
303
|
+
for param in self.parameters.method:
|
|
304
|
+
file_import.merge(
|
|
305
|
+
param.imports(
|
|
306
|
+
async_mode,
|
|
307
|
+
operation=self,
|
|
308
|
+
**kwargs,
|
|
309
|
+
)
|
|
310
|
+
)
|
|
311
|
+
for response in self.responses:
|
|
312
|
+
file_import.merge(response.imports(async_mode=async_mode, operation=self, **kwargs))
|
|
313
|
+
if self.code_model.options["models_mode"]:
|
|
314
|
+
for exception in self.exceptions:
|
|
315
|
+
file_import.merge(exception.imports(async_mode=async_mode, **kwargs))
|
|
316
|
+
|
|
317
|
+
if self.parameters.has_body and self.parameters.body_parameter.flattened:
|
|
318
|
+
file_import.merge(self.parameters.body_parameter.type.imports(operation=self, **kwargs))
|
|
319
|
+
if not async_mode:
|
|
320
|
+
for param in self.parameters.headers:
|
|
321
|
+
if param.wire_name.lower() == "repeatability-request-id":
|
|
322
|
+
file_import.add_import("uuid", ImportType.STDLIB)
|
|
323
|
+
elif param.wire_name.lower() == "repeatability-first-sent":
|
|
324
|
+
file_import.add_import("datetime", ImportType.STDLIB)
|
|
325
|
+
|
|
326
|
+
# Exceptions
|
|
327
|
+
errors = [
|
|
328
|
+
"map_error",
|
|
329
|
+
"HttpResponseError",
|
|
330
|
+
"ClientAuthenticationError",
|
|
331
|
+
"ResourceNotFoundError",
|
|
332
|
+
"ResourceExistsError",
|
|
333
|
+
"ResourceNotModifiedError",
|
|
334
|
+
]
|
|
335
|
+
if self.stream_value:
|
|
336
|
+
errors.extend(["StreamConsumedError", "StreamClosedError"])
|
|
337
|
+
for error in errors:
|
|
338
|
+
file_import.add_submodule_import("exceptions", error, ImportType.SDKCORE)
|
|
339
|
+
if self.code_model.options["azure_arm"]:
|
|
340
|
+
file_import.add_submodule_import("azure.mgmt.core.exceptions", "ARMErrorFormat", ImportType.SDKCORE)
|
|
341
|
+
file_import.add_mutable_mapping_import()
|
|
342
|
+
|
|
343
|
+
if self.has_kwargs_to_pop_with_default(
|
|
344
|
+
self.parameters.kwargs_to_pop, ParameterLocation.HEADER # type: ignore
|
|
345
|
+
) or self.has_kwargs_to_pop_with_default(
|
|
346
|
+
self.parameters.kwargs_to_pop, ParameterLocation.QUERY # type: ignore
|
|
347
|
+
):
|
|
348
|
+
file_import.add_submodule_import(
|
|
349
|
+
"utils",
|
|
350
|
+
"case_insensitive_dict",
|
|
351
|
+
ImportType.SDKCORE,
|
|
352
|
+
)
|
|
353
|
+
if self.deprecated:
|
|
354
|
+
file_import.add_import("warnings", ImportType.STDLIB)
|
|
355
|
+
|
|
356
|
+
relative_path = "..." if async_mode else ".."
|
|
357
|
+
if self.has_etag:
|
|
358
|
+
file_import.add_submodule_import(
|
|
359
|
+
"exceptions",
|
|
360
|
+
"ResourceModifiedError",
|
|
361
|
+
ImportType.SDKCORE,
|
|
362
|
+
)
|
|
363
|
+
if not async_mode:
|
|
364
|
+
file_import.add_submodule_import(f"{relative_path}_vendor", "prep_if_match", ImportType.LOCAL)
|
|
365
|
+
file_import.add_submodule_import(f"{relative_path}_vendor", "prep_if_none_match", ImportType.LOCAL)
|
|
366
|
+
if async_mode:
|
|
367
|
+
file_import.add_submodule_import(
|
|
368
|
+
"rest",
|
|
369
|
+
"AsyncHttpResponse",
|
|
370
|
+
ImportType.SDKCORE,
|
|
371
|
+
)
|
|
372
|
+
else:
|
|
373
|
+
file_import.add_submodule_import(
|
|
374
|
+
"rest",
|
|
375
|
+
"HttpResponse",
|
|
376
|
+
ImportType.SDKCORE,
|
|
377
|
+
)
|
|
378
|
+
if self.code_model.options["builders_visibility"] == "embedded" and not async_mode:
|
|
379
|
+
file_import.merge(self.request_builder.imports())
|
|
380
|
+
file_import.add_submodule_import(
|
|
381
|
+
f"{'' if self.code_model.is_azure_flavor else 'runtime.'}pipeline",
|
|
382
|
+
"PipelineResponse",
|
|
383
|
+
ImportType.SDKCORE,
|
|
384
|
+
)
|
|
385
|
+
file_import.add_submodule_import("rest", "HttpRequest", ImportType.SDKCORE)
|
|
386
|
+
file_import.add_submodule_import("typing", "Callable", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
387
|
+
file_import.add_submodule_import("typing", "Optional", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
388
|
+
file_import.add_submodule_import("typing", "Dict", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
389
|
+
file_import.add_submodule_import("typing", "TypeVar", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
390
|
+
if self.code_model.options["tracing"] and self.want_tracing and not async_mode:
|
|
391
|
+
file_import.add_submodule_import(
|
|
392
|
+
"azure.core.tracing.decorator",
|
|
393
|
+
"distributed_trace",
|
|
394
|
+
ImportType.SDKCORE,
|
|
395
|
+
)
|
|
396
|
+
file_import.merge(self.get_request_builder_import(self.request_builder, async_mode))
|
|
397
|
+
if self.overloads:
|
|
398
|
+
file_import.add_submodule_import("typing", "overload", ImportType.STDLIB)
|
|
399
|
+
if self.code_model.options["models_mode"] == "dpg":
|
|
400
|
+
if self.parameters.has_body:
|
|
401
|
+
if self.has_form_data_body:
|
|
402
|
+
file_import.add_submodule_import(relative_path, "_model_base", ImportType.LOCAL)
|
|
403
|
+
elif xml_serializable(self.parameters.body_parameter.default_content_type):
|
|
404
|
+
file_import.add_submodule_import(
|
|
405
|
+
f"{relative_path}_model_base",
|
|
406
|
+
"_get_element",
|
|
407
|
+
ImportType.LOCAL,
|
|
408
|
+
)
|
|
409
|
+
elif json_serializable(self.parameters.body_parameter.default_content_type):
|
|
410
|
+
file_import.add_submodule_import(
|
|
411
|
+
f"{relative_path}_model_base",
|
|
412
|
+
"SdkJSONEncoder",
|
|
413
|
+
ImportType.LOCAL,
|
|
414
|
+
)
|
|
415
|
+
file_import.add_import("json", ImportType.STDLIB)
|
|
416
|
+
if any(xml_serializable(str(r.default_content_type)) for r in self.responses):
|
|
417
|
+
file_import.add_submodule_import(f"{relative_path}_model_base", "_deserialize_xml", ImportType.LOCAL)
|
|
418
|
+
elif any(r.type for r in self.responses):
|
|
419
|
+
file_import.add_submodule_import(f"{relative_path}_model_base", "_deserialize", ImportType.LOCAL)
|
|
420
|
+
if self.default_error_deserialization or self.non_default_errors:
|
|
421
|
+
file_import.add_submodule_import(
|
|
422
|
+
f"{relative_path}_model_base", "_failsafe_deserialize", ImportType.LOCAL
|
|
423
|
+
)
|
|
424
|
+
return file_import
|
|
425
|
+
|
|
426
|
+
def get_response_from_status(self, status_code: Optional[Union[str, int]]) -> ResponseType:
|
|
427
|
+
try:
|
|
428
|
+
return next(r for r in self.responses if status_code in r.status_codes)
|
|
429
|
+
except StopIteration as exc:
|
|
430
|
+
raise ValueError(f"Incorrect status code {status_code}, operation {self.name}") from exc
|
|
431
|
+
|
|
432
|
+
@property
|
|
433
|
+
def success_status_codes(self) -> List[Union[int, str, List[int]]]:
|
|
434
|
+
"""The list of all successfull status code."""
|
|
435
|
+
return sorted([code for response in self.responses for code in response.status_codes])
|
|
436
|
+
|
|
437
|
+
@property
|
|
438
|
+
def filename(self) -> str:
|
|
439
|
+
basename = self.group_name
|
|
440
|
+
if basename == "":
|
|
441
|
+
# in a mixin
|
|
442
|
+
basename = self.code_model.clients[0].legacy_filename
|
|
443
|
+
|
|
444
|
+
if basename == "operations" or self.code_model.options["combine_operation_files"]:
|
|
445
|
+
return "_operations"
|
|
446
|
+
return f"_{basename}_operations"
|
|
447
|
+
|
|
448
|
+
@property
|
|
449
|
+
def has_stream_response(self) -> bool:
|
|
450
|
+
return any(r.is_stream_response for r in self.responses)
|
|
451
|
+
|
|
452
|
+
@classmethod
|
|
453
|
+
def get_request_builder(cls, yaml_data: Dict[str, Any], client: "Client"):
|
|
454
|
+
return client.lookup_request_builder(id(yaml_data))
|
|
455
|
+
|
|
456
|
+
@classmethod
|
|
457
|
+
def from_yaml(
|
|
458
|
+
cls,
|
|
459
|
+
yaml_data: Dict[str, Any],
|
|
460
|
+
code_model: "CodeModel",
|
|
461
|
+
client: "Client",
|
|
462
|
+
):
|
|
463
|
+
name = yaml_data["name"]
|
|
464
|
+
request_builder = cls.get_request_builder(yaml_data, client)
|
|
465
|
+
responses = [cast(ResponseType, get_response(r, code_model)) for r in yaml_data["responses"]]
|
|
466
|
+
exceptions = [Response.from_yaml(e, code_model) for e in yaml_data["exceptions"]]
|
|
467
|
+
parameter_list = ParameterList.from_yaml(yaml_data, code_model)
|
|
468
|
+
overloads = [cls.from_yaml(overload, code_model, client) for overload in yaml_data.get("overloads", [])]
|
|
469
|
+
|
|
470
|
+
return cls(
|
|
471
|
+
yaml_data=yaml_data,
|
|
472
|
+
code_model=code_model,
|
|
473
|
+
client=client,
|
|
474
|
+
request_builder=request_builder,
|
|
475
|
+
name=name,
|
|
476
|
+
parameters=parameter_list,
|
|
477
|
+
overloads=overloads,
|
|
478
|
+
responses=responses,
|
|
479
|
+
exceptions=exceptions,
|
|
480
|
+
)
|
|
481
|
+
|
|
482
|
+
|
|
483
|
+
class Operation(OperationBase[Response]):
|
|
484
|
+
def imports(self, async_mode: bool, **kwargs: Any) -> FileImport:
|
|
485
|
+
file_import = super().imports(async_mode, **kwargs)
|
|
486
|
+
if self.abstract:
|
|
487
|
+
return file_import
|
|
488
|
+
if async_mode and self.code_model.options["tracing"] and self.want_tracing:
|
|
489
|
+
file_import.add_submodule_import(
|
|
490
|
+
"azure.core.tracing.decorator_async",
|
|
491
|
+
"distributed_trace_async",
|
|
492
|
+
ImportType.SDKCORE,
|
|
493
|
+
)
|
|
494
|
+
if self.has_response_body and not self.has_optional_return_type and not self.code_model.options["models_mode"]:
|
|
495
|
+
file_import.add_submodule_import("typing", "cast", ImportType.STDLIB)
|
|
496
|
+
|
|
497
|
+
return file_import
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
def get_operation(yaml_data: Dict[str, Any], code_model: "CodeModel", client: "Client") -> "OperationType":
|
|
501
|
+
if yaml_data["discriminator"] == "lropaging":
|
|
502
|
+
from .lro_paging_operation import LROPagingOperation as OperationCls
|
|
503
|
+
elif yaml_data["discriminator"] == "lro":
|
|
504
|
+
from .lro_operation import LROOperation as OperationCls # type: ignore
|
|
505
|
+
elif yaml_data["discriminator"] == "paging":
|
|
506
|
+
from .paging_operation import PagingOperation as OperationCls # type: ignore
|
|
507
|
+
else:
|
|
508
|
+
from . import Operation as OperationCls # type: ignore
|
|
509
|
+
return OperationCls.from_yaml(yaml_data, code_model, client)
|
|
@@ -0,0 +1,184 @@
|
|
|
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 Dict, List, Any, TYPE_CHECKING
|
|
7
|
+
|
|
8
|
+
from .utils import OrderedSet
|
|
9
|
+
|
|
10
|
+
from .base import BaseModel
|
|
11
|
+
from .operation import get_operation
|
|
12
|
+
from .imports import FileImport, ImportType, TypingSection
|
|
13
|
+
from .utils import add_to_pylint_disable
|
|
14
|
+
from .lro_operation import LROOperation
|
|
15
|
+
from .lro_paging_operation import LROPagingOperation
|
|
16
|
+
from ...utils import NAME_LENGTH_LIMIT
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from .code_model import CodeModel
|
|
20
|
+
from .client import Client
|
|
21
|
+
from . import OperationType
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class OperationGroup(BaseModel):
|
|
25
|
+
"""Represent an operation group."""
|
|
26
|
+
|
|
27
|
+
def __init__(
|
|
28
|
+
self,
|
|
29
|
+
yaml_data: Dict[str, Any],
|
|
30
|
+
code_model: "CodeModel",
|
|
31
|
+
client: "Client",
|
|
32
|
+
operations: List["OperationType"],
|
|
33
|
+
api_versions: List[str],
|
|
34
|
+
) -> None:
|
|
35
|
+
super().__init__(yaml_data, code_model)
|
|
36
|
+
self.client = client
|
|
37
|
+
self.class_name: str = yaml_data["className"]
|
|
38
|
+
self.identify_name: str = yaml_data["identifyName"]
|
|
39
|
+
self.property_name: str = yaml_data["propertyName"]
|
|
40
|
+
self.operations = operations
|
|
41
|
+
self.api_versions = api_versions
|
|
42
|
+
self.operation_groups: List[OperationGroup] = []
|
|
43
|
+
if self.code_model.options["show_operations"]:
|
|
44
|
+
self.operation_groups = [
|
|
45
|
+
OperationGroup.from_yaml(op_group, code_model, client)
|
|
46
|
+
for op_group in self.yaml_data.get("operationGroups", [])
|
|
47
|
+
]
|
|
48
|
+
self.link_lro_initial_operations()
|
|
49
|
+
|
|
50
|
+
@property
|
|
51
|
+
def has_abstract_operations(self) -> bool:
|
|
52
|
+
return any(o for o in self.operations if o.abstract) or any(
|
|
53
|
+
operation_group.has_abstract_operations for operation_group in self.operation_groups
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
@property
|
|
57
|
+
def has_non_abstract_operations(self) -> bool:
|
|
58
|
+
return any(o for o in self.operations if not o.abstract) or any(
|
|
59
|
+
operation_group.has_non_abstract_operations for operation_group in self.operation_groups
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
@property
|
|
63
|
+
def base_class(self) -> str:
|
|
64
|
+
base_classes: List[str] = []
|
|
65
|
+
if self.is_mixin:
|
|
66
|
+
base_classes.append(f"{self.client.name}MixinABC")
|
|
67
|
+
return ", ".join(base_classes)
|
|
68
|
+
|
|
69
|
+
def imports_for_multiapi(self, async_mode: bool) -> FileImport:
|
|
70
|
+
file_import = FileImport(self.code_model)
|
|
71
|
+
relative_path = ".." if async_mode else "."
|
|
72
|
+
for operation in self.operations:
|
|
73
|
+
file_import.merge(operation.imports_for_multiapi(async_mode, relative_path=relative_path))
|
|
74
|
+
if (self.code_model.model_types or self.code_model.enums) and self.code_model.options[
|
|
75
|
+
"models_mode"
|
|
76
|
+
] == "msrest":
|
|
77
|
+
file_import.add_submodule_import(relative_path, "models", ImportType.LOCAL, alias="_models")
|
|
78
|
+
return file_import
|
|
79
|
+
|
|
80
|
+
def pylint_disable(self) -> str:
|
|
81
|
+
retval: str = ""
|
|
82
|
+
if self.has_abstract_operations:
|
|
83
|
+
retval = add_to_pylint_disable(retval, "abstract-class-instantiated")
|
|
84
|
+
if len(self.operations) > 20:
|
|
85
|
+
retval = add_to_pylint_disable(retval, "too-many-public-methods")
|
|
86
|
+
if len(self.class_name) > NAME_LENGTH_LIMIT:
|
|
87
|
+
retval = add_to_pylint_disable(retval, "name-too-long")
|
|
88
|
+
if len(self.operation_groups) > 6:
|
|
89
|
+
retval = add_to_pylint_disable(retval, "too-many-instance-attributes")
|
|
90
|
+
return retval
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def need_validation(self) -> bool:
|
|
94
|
+
"""Whether any of its operations need validation"""
|
|
95
|
+
return any(o for o in self.operations if o.need_validation)
|
|
96
|
+
|
|
97
|
+
def imports(self, async_mode: bool) -> FileImport:
|
|
98
|
+
file_import = FileImport(self.code_model)
|
|
99
|
+
|
|
100
|
+
relative_path = ("..." if async_mode else "..") + ("." if self.client.is_subclient else "")
|
|
101
|
+
for operation in self.operations:
|
|
102
|
+
file_import.merge(operation.imports(async_mode, relative_path=relative_path))
|
|
103
|
+
if not self.code_model.options["combine_operation_files"]:
|
|
104
|
+
for og in self.operation_groups:
|
|
105
|
+
file_import.add_submodule_import(
|
|
106
|
+
".",
|
|
107
|
+
og.class_name,
|
|
108
|
+
ImportType.LOCAL,
|
|
109
|
+
)
|
|
110
|
+
# for multiapi
|
|
111
|
+
if (
|
|
112
|
+
(self.code_model.public_model_types)
|
|
113
|
+
and self.code_model.options["models_mode"] == "msrest"
|
|
114
|
+
and not self.is_mixin
|
|
115
|
+
):
|
|
116
|
+
file_import.add_submodule_import(relative_path, "models", ImportType.LOCAL, alias="_models")
|
|
117
|
+
if self.is_mixin:
|
|
118
|
+
file_import.add_submodule_import(".._vendor", f"{self.client.name}MixinABC", ImportType.LOCAL)
|
|
119
|
+
if self.has_abstract_operations:
|
|
120
|
+
file_import.add_submodule_import(".._vendor", "raise_if_not_implemented", ImportType.LOCAL)
|
|
121
|
+
if all(o.abstract for o in self.operations):
|
|
122
|
+
return file_import
|
|
123
|
+
file_import.add_submodule_import("typing", "TypeVar", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
124
|
+
file_import.define_mypy_type("T", "TypeVar('T')")
|
|
125
|
+
type_value = "Optional[Callable[[PipelineResponse[HttpRequest, {}HttpResponse], T, Dict[str, Any]], Any]]"
|
|
126
|
+
file_import.define_mypy_type("ClsType", type_value.format(""), type_value.format("Async"))
|
|
127
|
+
return file_import
|
|
128
|
+
|
|
129
|
+
@property
|
|
130
|
+
def filename(self) -> str:
|
|
131
|
+
return self.operations[0].filename
|
|
132
|
+
|
|
133
|
+
@property
|
|
134
|
+
def is_mixin(self) -> bool:
|
|
135
|
+
"""The operation group with no name is the direct client methods."""
|
|
136
|
+
return self.identify_name == ""
|
|
137
|
+
|
|
138
|
+
def link_lro_initial_operations(self) -> None:
|
|
139
|
+
"""Link each LRO operation to its initial operation"""
|
|
140
|
+
for operation_group in self.operation_groups:
|
|
141
|
+
for operation in operation_group.operations:
|
|
142
|
+
if isinstance(operation, (LROOperation, LROPagingOperation)):
|
|
143
|
+
operation.initial_operation = self.lookup_operation(id(operation.yaml_data["initialOperation"]))
|
|
144
|
+
|
|
145
|
+
def lookup_operation(self, operation_id: int) -> "OperationType":
|
|
146
|
+
try:
|
|
147
|
+
return next(o for og in self.operation_groups for o in og.operations if id(o.yaml_data) == operation_id)
|
|
148
|
+
except StopIteration as exc:
|
|
149
|
+
raise KeyError(f"No operation with id {operation_id} found.") from exc
|
|
150
|
+
|
|
151
|
+
@property
|
|
152
|
+
def lro_operations(self) -> List["OperationType"]:
|
|
153
|
+
return [operation for operation in self.operations if operation.operation_type in ("lro", "lropaging")] + [
|
|
154
|
+
operation for operation_group in self.operation_groups for operation in operation_group.lro_operations
|
|
155
|
+
]
|
|
156
|
+
|
|
157
|
+
@property
|
|
158
|
+
def has_operations(self) -> bool:
|
|
159
|
+
return any(operation_group.has_operations for operation_group in self.operation_groups) or bool(self.operations)
|
|
160
|
+
|
|
161
|
+
@property
|
|
162
|
+
def has_form_data_body(self) -> bool:
|
|
163
|
+
operations = self.operations + [o for og in self.operation_groups for o in og.operations]
|
|
164
|
+
return any(operation.has_form_data_body for operation in operations)
|
|
165
|
+
|
|
166
|
+
@classmethod
|
|
167
|
+
def from_yaml(
|
|
168
|
+
cls,
|
|
169
|
+
yaml_data: Dict[str, Any],
|
|
170
|
+
code_model: "CodeModel",
|
|
171
|
+
client: "Client",
|
|
172
|
+
) -> "OperationGroup":
|
|
173
|
+
operations = [get_operation(o, code_model, client) for o in yaml_data["operations"]]
|
|
174
|
+
api_versions: OrderedSet[str] = {}
|
|
175
|
+
for operation in operations:
|
|
176
|
+
for api_version in operation.api_versions:
|
|
177
|
+
api_versions[api_version] = None
|
|
178
|
+
return cls(
|
|
179
|
+
yaml_data=yaml_data,
|
|
180
|
+
code_model=code_model,
|
|
181
|
+
client=client,
|
|
182
|
+
operations=operations,
|
|
183
|
+
api_versions=list(api_versions.keys()),
|
|
184
|
+
)
|