@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,155 @@
|
|
|
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, Optional, Union, TYPE_CHECKING, cast, TypeVar
|
|
7
|
+
|
|
8
|
+
from .operation import Operation, OperationBase
|
|
9
|
+
from .response import PagingResponse, LROPagingResponse, Response
|
|
10
|
+
from .request_builder import (
|
|
11
|
+
OverloadedRequestBuilder,
|
|
12
|
+
RequestBuilder,
|
|
13
|
+
get_request_builder,
|
|
14
|
+
)
|
|
15
|
+
from .imports import ImportType, FileImport, TypingSection
|
|
16
|
+
from .parameter_list import ParameterList
|
|
17
|
+
from .model_type import ModelType
|
|
18
|
+
from .list_type import ListType
|
|
19
|
+
|
|
20
|
+
if TYPE_CHECKING:
|
|
21
|
+
from .code_model import CodeModel
|
|
22
|
+
from .client import Client
|
|
23
|
+
|
|
24
|
+
PagingResponseType = TypeVar("PagingResponseType", bound=Union[PagingResponse, LROPagingResponse])
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class PagingOperationBase(OperationBase[PagingResponseType]):
|
|
28
|
+
def __init__(
|
|
29
|
+
self,
|
|
30
|
+
yaml_data: Dict[str, Any],
|
|
31
|
+
code_model: "CodeModel",
|
|
32
|
+
client: "Client",
|
|
33
|
+
name: str,
|
|
34
|
+
request_builder: RequestBuilder,
|
|
35
|
+
parameters: ParameterList,
|
|
36
|
+
responses: List[PagingResponseType],
|
|
37
|
+
exceptions: List[Response],
|
|
38
|
+
*,
|
|
39
|
+
overloads: Optional[List[Operation]] = None,
|
|
40
|
+
override_success_response_to_200: bool = False,
|
|
41
|
+
) -> None:
|
|
42
|
+
super().__init__(
|
|
43
|
+
code_model=code_model,
|
|
44
|
+
client=client,
|
|
45
|
+
yaml_data=yaml_data,
|
|
46
|
+
name=name,
|
|
47
|
+
request_builder=request_builder,
|
|
48
|
+
parameters=parameters,
|
|
49
|
+
responses=responses,
|
|
50
|
+
exceptions=exceptions,
|
|
51
|
+
overloads=overloads,
|
|
52
|
+
)
|
|
53
|
+
self.next_request_builder: Optional[Union[RequestBuilder, OverloadedRequestBuilder]] = (
|
|
54
|
+
get_request_builder(self.yaml_data["nextOperation"], code_model, client)
|
|
55
|
+
if self.yaml_data.get("nextOperation")
|
|
56
|
+
else None
|
|
57
|
+
)
|
|
58
|
+
self.override_success_response_to_200 = override_success_response_to_200
|
|
59
|
+
self.pager_sync: str = yaml_data.get("pagerSync") or f"{self.code_model.core_library}.paging.ItemPaged"
|
|
60
|
+
self.pager_async: str = yaml_data.get("pagerAsync") or f"{self.code_model.core_library}.paging.AsyncItemPaged"
|
|
61
|
+
|
|
62
|
+
def _get_attr_name(self, wire_name: str) -> str:
|
|
63
|
+
response_type = self.responses[0].type
|
|
64
|
+
if not response_type:
|
|
65
|
+
raise ValueError(f"Can't find a matching property in response for {wire_name}")
|
|
66
|
+
if response_type.type == "list":
|
|
67
|
+
response_type = cast(ListType, response_type).element_type
|
|
68
|
+
try:
|
|
69
|
+
return next(p.client_name for p in cast(ModelType, response_type).properties if p.wire_name == wire_name)
|
|
70
|
+
except StopIteration as exc:
|
|
71
|
+
raise ValueError(f"Can't find a matching property in response for {wire_name}") from exc
|
|
72
|
+
|
|
73
|
+
def get_pager(self, async_mode: bool) -> str:
|
|
74
|
+
return self.responses[0].get_pager(async_mode)
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def continuation_token_name(self) -> Optional[str]:
|
|
78
|
+
wire_name = self.yaml_data.get("continuationTokenName")
|
|
79
|
+
if not wire_name:
|
|
80
|
+
# That's an ok scenario, it just means no next page possible
|
|
81
|
+
return None
|
|
82
|
+
if self.code_model.options["models_mode"] == "msrest":
|
|
83
|
+
return self._get_attr_name(wire_name)
|
|
84
|
+
return wire_name
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def item_name(self) -> str:
|
|
88
|
+
wire_name = self.yaml_data["itemName"]
|
|
89
|
+
if self.code_model.options["models_mode"] == "msrest":
|
|
90
|
+
# we don't use the paging model for dpg
|
|
91
|
+
return self._get_attr_name(wire_name)
|
|
92
|
+
return wire_name
|
|
93
|
+
|
|
94
|
+
@property
|
|
95
|
+
def item_type(self) -> ModelType:
|
|
96
|
+
try:
|
|
97
|
+
item_type_yaml = self.yaml_data["itemType"]
|
|
98
|
+
except KeyError as e:
|
|
99
|
+
raise ValueError("Only call this for DPG paging model deserialization") from e
|
|
100
|
+
return cast(ModelType, self.code_model.types_map[id(item_type_yaml)])
|
|
101
|
+
|
|
102
|
+
@property
|
|
103
|
+
def operation_type(self) -> str:
|
|
104
|
+
return "paging"
|
|
105
|
+
|
|
106
|
+
def cls_type_annotation(self, *, async_mode: bool) -> str:
|
|
107
|
+
return f"ClsType[{Response.type_annotation(self.responses[0], async_mode=async_mode)}]"
|
|
108
|
+
|
|
109
|
+
def _imports_shared(self, async_mode: bool, **kwargs: Any) -> FileImport:
|
|
110
|
+
file_import = super()._imports_shared(async_mode, **kwargs)
|
|
111
|
+
if async_mode:
|
|
112
|
+
file_import.add_submodule_import("typing", "AsyncIterable", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
113
|
+
else:
|
|
114
|
+
file_import.add_submodule_import("typing", "Iterable", ImportType.STDLIB, TypingSection.CONDITIONAL)
|
|
115
|
+
if (
|
|
116
|
+
self.next_request_builder
|
|
117
|
+
and self.code_model.options["builders_visibility"] == "embedded"
|
|
118
|
+
and not async_mode
|
|
119
|
+
):
|
|
120
|
+
file_import.merge(self.next_request_builder.imports())
|
|
121
|
+
return file_import
|
|
122
|
+
|
|
123
|
+
@property
|
|
124
|
+
def has_optional_return_type(self) -> bool:
|
|
125
|
+
return False
|
|
126
|
+
|
|
127
|
+
def imports(self, async_mode: bool, **kwargs: Any) -> FileImport:
|
|
128
|
+
if self.abstract:
|
|
129
|
+
return FileImport(self.code_model)
|
|
130
|
+
file_import = self._imports_shared(async_mode, **kwargs)
|
|
131
|
+
file_import.merge(super().imports(async_mode, **kwargs))
|
|
132
|
+
if self.code_model.options["tracing"] and self.want_tracing:
|
|
133
|
+
file_import.add_submodule_import(
|
|
134
|
+
"azure.core.tracing.decorator",
|
|
135
|
+
"distributed_trace",
|
|
136
|
+
ImportType.SDKCORE,
|
|
137
|
+
)
|
|
138
|
+
if self.next_request_builder:
|
|
139
|
+
file_import.merge(self.get_request_builder_import(self.next_request_builder, async_mode))
|
|
140
|
+
elif any(p.is_api_version for p in self.client.parameters):
|
|
141
|
+
file_import.add_import("urllib.parse", ImportType.STDLIB)
|
|
142
|
+
file_import.add_submodule_import(
|
|
143
|
+
"utils",
|
|
144
|
+
"case_insensitive_dict",
|
|
145
|
+
ImportType.SDKCORE,
|
|
146
|
+
)
|
|
147
|
+
if self.code_model.options["models_mode"] == "dpg":
|
|
148
|
+
relative_path = "..." if async_mode else ".."
|
|
149
|
+
file_import.merge(self.item_type.imports(**kwargs))
|
|
150
|
+
if self.default_error_deserialization or any(r.type for r in self.responses):
|
|
151
|
+
file_import.add_submodule_import(f"{relative_path}_model_base", "_deserialize", ImportType.LOCAL)
|
|
152
|
+
return file_import
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
class PagingOperation(PagingOperationBase[PagingResponse]): ...
|
|
@@ -0,0 +1,412 @@
|
|
|
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
|
+
import abc
|
|
7
|
+
from enum import Enum
|
|
8
|
+
|
|
9
|
+
from typing import (
|
|
10
|
+
Dict,
|
|
11
|
+
Any,
|
|
12
|
+
TYPE_CHECKING,
|
|
13
|
+
List,
|
|
14
|
+
Optional,
|
|
15
|
+
TypeVar,
|
|
16
|
+
Union,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
from .imports import FileImport, ImportType, TypingSection
|
|
20
|
+
from .base import BaseModel
|
|
21
|
+
from .base import BaseType
|
|
22
|
+
from .constant_type import ConstantType
|
|
23
|
+
from .utils import add_to_description
|
|
24
|
+
from .combined_type import CombinedType
|
|
25
|
+
from .model_type import JSONModelType
|
|
26
|
+
|
|
27
|
+
if TYPE_CHECKING:
|
|
28
|
+
from .code_model import CodeModel
|
|
29
|
+
from .request_builder_parameter import RequestBuilderBodyParameter
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ParameterLocation(str, Enum):
|
|
33
|
+
HEADER = "header"
|
|
34
|
+
PATH = "path"
|
|
35
|
+
ENDPOINT_PATH = "endpointPath"
|
|
36
|
+
QUERY = "query"
|
|
37
|
+
BODY = "body"
|
|
38
|
+
OTHER = "other"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class ParameterMethodLocation(str, Enum):
|
|
42
|
+
POSITIONAL = "positional"
|
|
43
|
+
KEYWORD_ONLY = "keywordOnly"
|
|
44
|
+
KWARG = "kwarg"
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class ParameterDelimeter(str, Enum):
|
|
48
|
+
SPACE = "space"
|
|
49
|
+
PIPE = "pipe"
|
|
50
|
+
TAB = "tab"
|
|
51
|
+
COMMA = "comma"
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
class _ParameterBase(BaseModel, abc.ABC): # pylint: disable=too-many-instance-attributes
|
|
55
|
+
"""Base class for all parameters"""
|
|
56
|
+
|
|
57
|
+
def __init__(
|
|
58
|
+
self,
|
|
59
|
+
yaml_data: Dict[str, Any],
|
|
60
|
+
code_model: "CodeModel",
|
|
61
|
+
type: BaseType,
|
|
62
|
+
) -> None:
|
|
63
|
+
super().__init__(yaml_data, code_model)
|
|
64
|
+
self.wire_name: str = yaml_data.get("wireName", "")
|
|
65
|
+
self.client_name: str = self.yaml_data["clientName"]
|
|
66
|
+
self.optional: bool = self.yaml_data["optional"]
|
|
67
|
+
self.implementation: str = yaml_data.get("implementation", None)
|
|
68
|
+
self.location: ParameterLocation = self.yaml_data["location"]
|
|
69
|
+
self.client_default_value = self.yaml_data.get("clientDefaultValue", None)
|
|
70
|
+
self.in_docstring = self.yaml_data.get("inDocstring", True)
|
|
71
|
+
self.type = type
|
|
72
|
+
if self.client_default_value is None:
|
|
73
|
+
self.client_default_value = self.type.client_default_value
|
|
74
|
+
# name of grouper if it is grouped by another parameter
|
|
75
|
+
self.grouped_by: Optional[str] = self.yaml_data.get("groupedBy")
|
|
76
|
+
# property matching property name to parameter name for grouping params
|
|
77
|
+
# and flattened body params
|
|
78
|
+
self.property_to_parameter_name: Optional[Dict[str, str]] = self.yaml_data.get("propertyToParameterName")
|
|
79
|
+
self.flattened: bool = self.yaml_data.get("flattened", False)
|
|
80
|
+
self.in_flattened_body: bool = self.yaml_data.get("inFlattenedBody", False)
|
|
81
|
+
self.grouper: bool = self.yaml_data.get("grouper", False)
|
|
82
|
+
self.check_client_input: bool = self.yaml_data.get("checkClientInput", False)
|
|
83
|
+
self.added_on: Optional[str] = self.yaml_data.get("addedOn")
|
|
84
|
+
self.is_api_version: bool = self.yaml_data.get("isApiVersion", False)
|
|
85
|
+
self.in_overload: bool = self.yaml_data.get("inOverload", False)
|
|
86
|
+
self.default_to_unset_sentinel: bool = self.yaml_data.get("defaultToUnsetSentinel", False)
|
|
87
|
+
self.hide_in_method: bool = self.yaml_data.get("hideInMethod", False)
|
|
88
|
+
|
|
89
|
+
def get_declaration(self, value: Any = None) -> Any:
|
|
90
|
+
return self.type.get_declaration(value)
|
|
91
|
+
|
|
92
|
+
@property
|
|
93
|
+
def hide_in_operation_signature(self) -> bool:
|
|
94
|
+
return False
|
|
95
|
+
|
|
96
|
+
@property
|
|
97
|
+
def constant(self) -> bool:
|
|
98
|
+
"""Returns whether a parameter is a constant or not.
|
|
99
|
+
Checking to see if it's required, because if not, we don't consider it
|
|
100
|
+
a constant because it can have a value of None.
|
|
101
|
+
"""
|
|
102
|
+
return (not self.optional or self.is_api_version) and isinstance(self.type, ConstantType)
|
|
103
|
+
|
|
104
|
+
@property
|
|
105
|
+
def description(self) -> str:
|
|
106
|
+
base_description = self.yaml_data["description"]
|
|
107
|
+
type_description = self.type.description(is_operation_file=True)
|
|
108
|
+
if type_description:
|
|
109
|
+
base_description = add_to_description(base_description, type_description)
|
|
110
|
+
if self.optional and isinstance(self.type, ConstantType):
|
|
111
|
+
base_description = add_to_description(
|
|
112
|
+
base_description,
|
|
113
|
+
f"Known values are {self.get_declaration()} and None.",
|
|
114
|
+
)
|
|
115
|
+
if not (self.optional or self.client_default_value):
|
|
116
|
+
base_description = add_to_description(base_description, "Required.")
|
|
117
|
+
if self.client_default_value is not None:
|
|
118
|
+
base_description = add_to_description(
|
|
119
|
+
base_description,
|
|
120
|
+
f"Default value is {self.client_default_value_declaration}.",
|
|
121
|
+
)
|
|
122
|
+
if self.optional and self.client_default_value is None:
|
|
123
|
+
base_description = add_to_description(
|
|
124
|
+
base_description,
|
|
125
|
+
f"Default value is {self.client_default_value_declaration}.",
|
|
126
|
+
)
|
|
127
|
+
if self.constant:
|
|
128
|
+
base_description = add_to_description(
|
|
129
|
+
base_description,
|
|
130
|
+
"Note that overriding this default value may result in unsupported behavior.",
|
|
131
|
+
)
|
|
132
|
+
return base_description
|
|
133
|
+
|
|
134
|
+
@property
|
|
135
|
+
def client_default_value_declaration(self):
|
|
136
|
+
"""Declaration of parameter's client default value"""
|
|
137
|
+
if self.client_default_value is None:
|
|
138
|
+
return None
|
|
139
|
+
return self.get_declaration(self.client_default_value)
|
|
140
|
+
|
|
141
|
+
def type_annotation(self, **kwargs: Any) -> str:
|
|
142
|
+
kwargs["is_operation_file"] = True
|
|
143
|
+
# special logic for api-version parameter
|
|
144
|
+
if self.is_api_version:
|
|
145
|
+
type_annotation = "str"
|
|
146
|
+
else:
|
|
147
|
+
type_annotation = self.type.type_annotation(**kwargs)
|
|
148
|
+
if self.optional and self.client_default_value is None:
|
|
149
|
+
return f"Optional[{type_annotation}]"
|
|
150
|
+
return type_annotation
|
|
151
|
+
|
|
152
|
+
def docstring_text(self, **kwargs: Any) -> str:
|
|
153
|
+
return self.type.docstring_text(**kwargs)
|
|
154
|
+
|
|
155
|
+
def docstring_type(self, **kwargs: Any) -> str:
|
|
156
|
+
return self.type.docstring_type(**kwargs)
|
|
157
|
+
|
|
158
|
+
@property
|
|
159
|
+
def serialization_type(self) -> str:
|
|
160
|
+
return self.type.serialization_type
|
|
161
|
+
|
|
162
|
+
def _imports_shared(self, async_mode: bool, **_: Any) -> FileImport:
|
|
163
|
+
file_import = FileImport(self.code_model)
|
|
164
|
+
if self.optional and self.client_default_value is None:
|
|
165
|
+
file_import.add_submodule_import("typing", "Optional", ImportType.STDLIB)
|
|
166
|
+
if self.added_on and self.implementation != "Client":
|
|
167
|
+
file_import.add_submodule_import(
|
|
168
|
+
f"{'.' if async_mode else ''}.._validation",
|
|
169
|
+
"api_version_validation",
|
|
170
|
+
ImportType.LOCAL,
|
|
171
|
+
)
|
|
172
|
+
if isinstance(self.type, CombinedType) and self.type.name:
|
|
173
|
+
file_import.add_submodule_import(
|
|
174
|
+
"..." if async_mode else "..",
|
|
175
|
+
"_types",
|
|
176
|
+
ImportType.LOCAL,
|
|
177
|
+
TypingSection.TYPING,
|
|
178
|
+
)
|
|
179
|
+
return file_import
|
|
180
|
+
|
|
181
|
+
def imports(self, async_mode: bool, **kwargs: Any) -> FileImport:
|
|
182
|
+
file_import = self._imports_shared(async_mode, **kwargs)
|
|
183
|
+
# special logic for api-version parameter
|
|
184
|
+
if not self.is_api_version:
|
|
185
|
+
file_import.merge(self.type.imports(async_mode=async_mode, **kwargs))
|
|
186
|
+
if self.default_to_unset_sentinel:
|
|
187
|
+
file_import.add_submodule_import("typing", "Any", ImportType.STDLIB)
|
|
188
|
+
file_import.define_mypy_type(
|
|
189
|
+
"_Unset: Any",
|
|
190
|
+
"object()",
|
|
191
|
+
)
|
|
192
|
+
return file_import
|
|
193
|
+
|
|
194
|
+
def imports_for_multiapi(self, async_mode: bool, **kwargs: Any) -> FileImport:
|
|
195
|
+
file_import = self._imports_shared(async_mode, **kwargs)
|
|
196
|
+
file_import.merge(self.type.imports_for_multiapi(async_mode=async_mode, **kwargs))
|
|
197
|
+
return file_import
|
|
198
|
+
|
|
199
|
+
@property
|
|
200
|
+
def method_location(self) -> ParameterMethodLocation:
|
|
201
|
+
raise NotImplementedError("Please implement in children")
|
|
202
|
+
|
|
203
|
+
@property
|
|
204
|
+
def description_keyword(self) -> str:
|
|
205
|
+
return "param" if self.method_location == ParameterMethodLocation.POSITIONAL else "keyword"
|
|
206
|
+
|
|
207
|
+
@property
|
|
208
|
+
def docstring_type_keyword(self) -> str:
|
|
209
|
+
return "type" if self.method_location == ParameterMethodLocation.POSITIONAL else "paramtype"
|
|
210
|
+
|
|
211
|
+
@property
|
|
212
|
+
@abc.abstractmethod
|
|
213
|
+
def in_method_signature(self) -> bool: ...
|
|
214
|
+
|
|
215
|
+
def method_signature(self, async_mode: bool) -> str:
|
|
216
|
+
type_annotation = self.type_annotation(async_mode=async_mode)
|
|
217
|
+
if self.client_default_value is not None or self.optional:
|
|
218
|
+
return f"{self.client_name}: {type_annotation} = {self.client_default_value_declaration},"
|
|
219
|
+
if self.default_to_unset_sentinel:
|
|
220
|
+
return f"{self.client_name}: {type_annotation} = _Unset,"
|
|
221
|
+
return f"{self.client_name}: {type_annotation},"
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
class BodyParameter(_ParameterBase):
|
|
225
|
+
"""Body parameter."""
|
|
226
|
+
|
|
227
|
+
@property
|
|
228
|
+
def entries(self) -> List["BodyParameter"]:
|
|
229
|
+
return [BodyParameter.from_yaml(e, self.code_model) for e in self.yaml_data.get("entries", [])]
|
|
230
|
+
|
|
231
|
+
@property
|
|
232
|
+
def is_form_data(self) -> bool:
|
|
233
|
+
# hacky, but rn in legacy, there is no formdata model type, it's just a dict
|
|
234
|
+
# with all of the entries splatted out
|
|
235
|
+
return (
|
|
236
|
+
self.type.is_form_data
|
|
237
|
+
or bool(self.entries)
|
|
238
|
+
or ("multipart/form-data" in self.content_types and self.code_model.options["from_typespec"])
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
@property
|
|
242
|
+
def is_partial_body(self) -> bool:
|
|
243
|
+
"""Whether it's part of a bigger body parameter, i.e. a MultipartBodyParameter"""
|
|
244
|
+
return self.yaml_data.get("isPartialBody", False)
|
|
245
|
+
|
|
246
|
+
@property
|
|
247
|
+
def method_location(self) -> ParameterMethodLocation:
|
|
248
|
+
return ParameterMethodLocation.KWARG if self.constant else ParameterMethodLocation.POSITIONAL
|
|
249
|
+
|
|
250
|
+
@property
|
|
251
|
+
def in_method_signature(self) -> bool:
|
|
252
|
+
if self.yaml_data.get("entries"):
|
|
253
|
+
# Right now, only legacy generates with multipart bodies and entries
|
|
254
|
+
# and legacy generates with the multipart body arguments splatted out
|
|
255
|
+
return False
|
|
256
|
+
return not (self.flattened or self.grouped_by)
|
|
257
|
+
|
|
258
|
+
@property
|
|
259
|
+
def content_types(self) -> List[str]:
|
|
260
|
+
return self.yaml_data["contentTypes"]
|
|
261
|
+
|
|
262
|
+
@property
|
|
263
|
+
def default_content_type(self) -> str:
|
|
264
|
+
return self.yaml_data["defaultContentType"]
|
|
265
|
+
|
|
266
|
+
@property
|
|
267
|
+
def has_json_model_type(self) -> bool:
|
|
268
|
+
if isinstance(self.type, CombinedType):
|
|
269
|
+
return self.type.target_model_subtype((JSONModelType,)) is not None
|
|
270
|
+
return isinstance(self.type, JSONModelType)
|
|
271
|
+
|
|
272
|
+
def imports(self, async_mode: bool, **kwargs: Any) -> FileImport:
|
|
273
|
+
file_import = super().imports(async_mode, **kwargs)
|
|
274
|
+
if self.is_form_data:
|
|
275
|
+
relative_path = "..." if async_mode else ".."
|
|
276
|
+
file_import.add_submodule_import(
|
|
277
|
+
f"{relative_path}_vendor",
|
|
278
|
+
"prepare_multipart_form_data",
|
|
279
|
+
ImportType.LOCAL,
|
|
280
|
+
)
|
|
281
|
+
file_import.add_submodule_import("typing", "List", ImportType.STDLIB)
|
|
282
|
+
return file_import
|
|
283
|
+
|
|
284
|
+
@classmethod
|
|
285
|
+
def from_yaml(cls, yaml_data: Dict[str, Any], code_model: "CodeModel") -> "BodyParameter":
|
|
286
|
+
return cls(
|
|
287
|
+
yaml_data=yaml_data,
|
|
288
|
+
code_model=code_model,
|
|
289
|
+
type=code_model.lookup_type(id(yaml_data["type"])),
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
EntryBodyParameterType = TypeVar("EntryBodyParameterType", bound=Union[BodyParameter, "RequestBuilderBodyParameter"])
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
class Parameter(_ParameterBase):
|
|
297
|
+
"""Basic Parameter class"""
|
|
298
|
+
|
|
299
|
+
def __init__(
|
|
300
|
+
self,
|
|
301
|
+
yaml_data: Dict[str, Any],
|
|
302
|
+
code_model: "CodeModel",
|
|
303
|
+
type: BaseType,
|
|
304
|
+
) -> None:
|
|
305
|
+
super().__init__(yaml_data, code_model, type=type)
|
|
306
|
+
|
|
307
|
+
self.skip_url_encoding: bool = self.yaml_data.get("skipUrlEncoding", False)
|
|
308
|
+
self.explode: bool = self.yaml_data.get("explode", False)
|
|
309
|
+
self.in_overridden: bool = self.yaml_data.get("inOverridden", False)
|
|
310
|
+
self.delimiter: Optional[ParameterDelimeter] = self.yaml_data.get("delimiter")
|
|
311
|
+
self._default_to_unset_sentinel: bool = False
|
|
312
|
+
|
|
313
|
+
@property
|
|
314
|
+
def hide_in_operation_signature(self) -> bool:
|
|
315
|
+
if self.code_model.options["version_tolerant"] and self.client_name == "maxpagesize":
|
|
316
|
+
return True
|
|
317
|
+
return False
|
|
318
|
+
|
|
319
|
+
@property
|
|
320
|
+
def in_method_signature(self) -> bool:
|
|
321
|
+
return not (self.wire_name == "Accept" or self.grouped_by or self.flattened)
|
|
322
|
+
|
|
323
|
+
@property
|
|
324
|
+
def full_client_name(self) -> str:
|
|
325
|
+
if self.implementation == "Client":
|
|
326
|
+
return f"self._config.{self.client_name}"
|
|
327
|
+
return self.client_name
|
|
328
|
+
|
|
329
|
+
@property
|
|
330
|
+
def xml_serialization_ctxt(self) -> str:
|
|
331
|
+
return self.type.xml_serialization_ctxt or ""
|
|
332
|
+
|
|
333
|
+
@property
|
|
334
|
+
def is_content_type(self) -> bool:
|
|
335
|
+
return bool(self.wire_name) and self.wire_name.lower() == "content-type"
|
|
336
|
+
|
|
337
|
+
@property
|
|
338
|
+
def method_location( # pylint: disable=too-many-return-statements
|
|
339
|
+
self,
|
|
340
|
+
) -> ParameterMethodLocation:
|
|
341
|
+
if not self.in_method_signature:
|
|
342
|
+
raise ValueError(f"Parameter '{self.client_name}' is not in the method.")
|
|
343
|
+
if self.code_model.options["models_mode"] == "dpg" and self.in_flattened_body:
|
|
344
|
+
return ParameterMethodLocation.KEYWORD_ONLY
|
|
345
|
+
if self.grouper:
|
|
346
|
+
return ParameterMethodLocation.POSITIONAL
|
|
347
|
+
if self.constant and self.wire_name != "Content-Type":
|
|
348
|
+
return ParameterMethodLocation.KWARG
|
|
349
|
+
if self.is_content_type:
|
|
350
|
+
if self.in_overload:
|
|
351
|
+
return ParameterMethodLocation.KEYWORD_ONLY
|
|
352
|
+
return ParameterMethodLocation.KWARG
|
|
353
|
+
query_or_header = self.location in (
|
|
354
|
+
ParameterLocation.HEADER,
|
|
355
|
+
ParameterLocation.QUERY,
|
|
356
|
+
)
|
|
357
|
+
if self.code_model.options["only_path_and_body_params_positional"] and query_or_header:
|
|
358
|
+
return ParameterMethodLocation.KEYWORD_ONLY
|
|
359
|
+
return ParameterMethodLocation.POSITIONAL
|
|
360
|
+
|
|
361
|
+
@classmethod
|
|
362
|
+
def from_yaml(cls, yaml_data: Dict[str, Any], code_model: "CodeModel"):
|
|
363
|
+
return cls(
|
|
364
|
+
yaml_data=yaml_data,
|
|
365
|
+
code_model=code_model,
|
|
366
|
+
type=code_model.lookup_type(id(yaml_data["type"])),
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
class ClientParameter(Parameter):
|
|
371
|
+
"""Client parameter"""
|
|
372
|
+
|
|
373
|
+
@property
|
|
374
|
+
def is_host(self) -> bool:
|
|
375
|
+
return self.wire_name == "$host"
|
|
376
|
+
|
|
377
|
+
@property
|
|
378
|
+
def method_location(self) -> ParameterMethodLocation:
|
|
379
|
+
if self.constant:
|
|
380
|
+
return ParameterMethodLocation.KWARG
|
|
381
|
+
if (
|
|
382
|
+
self.is_host
|
|
383
|
+
and (self.code_model.options["version_tolerant"] or self.code_model.options["low_level_client"])
|
|
384
|
+
and not self.code_model.options["azure_arm"]
|
|
385
|
+
):
|
|
386
|
+
# this means i am the base url
|
|
387
|
+
return ParameterMethodLocation.KEYWORD_ONLY
|
|
388
|
+
if (
|
|
389
|
+
self.client_default_value is not None
|
|
390
|
+
and self.code_model.options["from_typespec"]
|
|
391
|
+
and not self.code_model.options["azure_arm"]
|
|
392
|
+
):
|
|
393
|
+
return ParameterMethodLocation.KEYWORD_ONLY
|
|
394
|
+
return ParameterMethodLocation.POSITIONAL
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
class ConfigParameter(Parameter):
|
|
398
|
+
"""Config Parameter"""
|
|
399
|
+
|
|
400
|
+
@property
|
|
401
|
+
def in_method_signature(self) -> bool:
|
|
402
|
+
return not self.is_host
|
|
403
|
+
|
|
404
|
+
@property
|
|
405
|
+
def is_host(self) -> bool:
|
|
406
|
+
return self.wire_name == "$host"
|
|
407
|
+
|
|
408
|
+
@property
|
|
409
|
+
def method_location(self) -> ParameterMethodLocation:
|
|
410
|
+
if self.constant:
|
|
411
|
+
return ParameterMethodLocation.KWARG
|
|
412
|
+
return ParameterMethodLocation.POSITIONAL
|