elasticsearch9 9.0.0__py3-none-any.whl
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.
- elasticsearch9/__init__.py +98 -0
- elasticsearch9/_async/__init__.py +16 -0
- elasticsearch9/_async/client/__init__.py +6531 -0
- elasticsearch9/_async/client/_base.py +430 -0
- elasticsearch9/_async/client/async_search.py +637 -0
- elasticsearch9/_async/client/autoscaling.py +252 -0
- elasticsearch9/_async/client/cat.py +2995 -0
- elasticsearch9/_async/client/ccr.py +1043 -0
- elasticsearch9/_async/client/cluster.py +1223 -0
- elasticsearch9/_async/client/connector.py +1978 -0
- elasticsearch9/_async/client/dangling_indices.py +192 -0
- elasticsearch9/_async/client/enrich.py +291 -0
- elasticsearch9/_async/client/eql.py +359 -0
- elasticsearch9/_async/client/esql.py +490 -0
- elasticsearch9/_async/client/features.py +130 -0
- elasticsearch9/_async/client/fleet.py +658 -0
- elasticsearch9/_async/client/graph.py +113 -0
- elasticsearch9/_async/client/ilm.py +668 -0
- elasticsearch9/_async/client/indices.py +5582 -0
- elasticsearch9/_async/client/inference.py +2247 -0
- elasticsearch9/_async/client/ingest.py +766 -0
- elasticsearch9/_async/client/license.py +400 -0
- elasticsearch9/_async/client/logstash.py +176 -0
- elasticsearch9/_async/client/migration.py +160 -0
- elasticsearch9/_async/client/ml.py +5835 -0
- elasticsearch9/_async/client/monitoring.py +100 -0
- elasticsearch9/_async/client/nodes.py +543 -0
- elasticsearch9/_async/client/query_rules.py +485 -0
- elasticsearch9/_async/client/rollup.py +616 -0
- elasticsearch9/_async/client/search_application.py +574 -0
- elasticsearch9/_async/client/searchable_snapshots.py +313 -0
- elasticsearch9/_async/client/security.py +4688 -0
- elasticsearch9/_async/client/shutdown.py +268 -0
- elasticsearch9/_async/client/simulate.py +145 -0
- elasticsearch9/_async/client/slm.py +559 -0
- elasticsearch9/_async/client/snapshot.py +1338 -0
- elasticsearch9/_async/client/sql.py +469 -0
- elasticsearch9/_async/client/ssl.py +76 -0
- elasticsearch9/_async/client/synonyms.py +413 -0
- elasticsearch9/_async/client/tasks.py +295 -0
- elasticsearch9/_async/client/text_structure.py +664 -0
- elasticsearch9/_async/client/transform.py +922 -0
- elasticsearch9/_async/client/utils.py +48 -0
- elasticsearch9/_async/client/watcher.py +894 -0
- elasticsearch9/_async/client/xpack.py +134 -0
- elasticsearch9/_async/helpers.py +596 -0
- elasticsearch9/_otel.py +110 -0
- elasticsearch9/_sync/__init__.py +16 -0
- elasticsearch9/_sync/client/__init__.py +6529 -0
- elasticsearch9/_sync/client/_base.py +430 -0
- elasticsearch9/_sync/client/async_search.py +637 -0
- elasticsearch9/_sync/client/autoscaling.py +252 -0
- elasticsearch9/_sync/client/cat.py +2995 -0
- elasticsearch9/_sync/client/ccr.py +1043 -0
- elasticsearch9/_sync/client/cluster.py +1223 -0
- elasticsearch9/_sync/client/connector.py +1978 -0
- elasticsearch9/_sync/client/dangling_indices.py +192 -0
- elasticsearch9/_sync/client/enrich.py +291 -0
- elasticsearch9/_sync/client/eql.py +359 -0
- elasticsearch9/_sync/client/esql.py +490 -0
- elasticsearch9/_sync/client/features.py +130 -0
- elasticsearch9/_sync/client/fleet.py +658 -0
- elasticsearch9/_sync/client/graph.py +113 -0
- elasticsearch9/_sync/client/ilm.py +668 -0
- elasticsearch9/_sync/client/indices.py +5582 -0
- elasticsearch9/_sync/client/inference.py +2247 -0
- elasticsearch9/_sync/client/ingest.py +766 -0
- elasticsearch9/_sync/client/license.py +400 -0
- elasticsearch9/_sync/client/logstash.py +176 -0
- elasticsearch9/_sync/client/migration.py +160 -0
- elasticsearch9/_sync/client/ml.py +5835 -0
- elasticsearch9/_sync/client/monitoring.py +100 -0
- elasticsearch9/_sync/client/nodes.py +543 -0
- elasticsearch9/_sync/client/query_rules.py +485 -0
- elasticsearch9/_sync/client/rollup.py +616 -0
- elasticsearch9/_sync/client/search_application.py +574 -0
- elasticsearch9/_sync/client/searchable_snapshots.py +313 -0
- elasticsearch9/_sync/client/security.py +4688 -0
- elasticsearch9/_sync/client/shutdown.py +268 -0
- elasticsearch9/_sync/client/simulate.py +145 -0
- elasticsearch9/_sync/client/slm.py +559 -0
- elasticsearch9/_sync/client/snapshot.py +1338 -0
- elasticsearch9/_sync/client/sql.py +469 -0
- elasticsearch9/_sync/client/ssl.py +76 -0
- elasticsearch9/_sync/client/synonyms.py +413 -0
- elasticsearch9/_sync/client/tasks.py +295 -0
- elasticsearch9/_sync/client/text_structure.py +664 -0
- elasticsearch9/_sync/client/transform.py +922 -0
- elasticsearch9/_sync/client/utils.py +475 -0
- elasticsearch9/_sync/client/watcher.py +894 -0
- elasticsearch9/_sync/client/xpack.py +134 -0
- elasticsearch9/_utils.py +34 -0
- elasticsearch9/_version.py +18 -0
- elasticsearch9/client.py +126 -0
- elasticsearch9/compat.py +79 -0
- elasticsearch9/dsl/__init__.py +203 -0
- elasticsearch9/dsl/_async/__init__.py +16 -0
- elasticsearch9/dsl/_async/document.py +522 -0
- elasticsearch9/dsl/_async/faceted_search.py +50 -0
- elasticsearch9/dsl/_async/index.py +639 -0
- elasticsearch9/dsl/_async/mapping.py +49 -0
- elasticsearch9/dsl/_async/search.py +237 -0
- elasticsearch9/dsl/_async/update_by_query.py +47 -0
- elasticsearch9/dsl/_sync/__init__.py +16 -0
- elasticsearch9/dsl/_sync/document.py +514 -0
- elasticsearch9/dsl/_sync/faceted_search.py +50 -0
- elasticsearch9/dsl/_sync/index.py +597 -0
- elasticsearch9/dsl/_sync/mapping.py +49 -0
- elasticsearch9/dsl/_sync/search.py +230 -0
- elasticsearch9/dsl/_sync/update_by_query.py +45 -0
- elasticsearch9/dsl/aggs.py +3734 -0
- elasticsearch9/dsl/analysis.py +341 -0
- elasticsearch9/dsl/async_connections.py +37 -0
- elasticsearch9/dsl/connections.py +142 -0
- elasticsearch9/dsl/document.py +20 -0
- elasticsearch9/dsl/document_base.py +444 -0
- elasticsearch9/dsl/exceptions.py +32 -0
- elasticsearch9/dsl/faceted_search.py +28 -0
- elasticsearch9/dsl/faceted_search_base.py +489 -0
- elasticsearch9/dsl/field.py +4392 -0
- elasticsearch9/dsl/function.py +180 -0
- elasticsearch9/dsl/index.py +23 -0
- elasticsearch9/dsl/index_base.py +178 -0
- elasticsearch9/dsl/mapping.py +19 -0
- elasticsearch9/dsl/mapping_base.py +219 -0
- elasticsearch9/dsl/query.py +2822 -0
- elasticsearch9/dsl/response/__init__.py +388 -0
- elasticsearch9/dsl/response/aggs.py +100 -0
- elasticsearch9/dsl/response/hit.py +53 -0
- elasticsearch9/dsl/search.py +20 -0
- elasticsearch9/dsl/search_base.py +1053 -0
- elasticsearch9/dsl/serializer.py +34 -0
- elasticsearch9/dsl/types.py +6453 -0
- elasticsearch9/dsl/update_by_query.py +19 -0
- elasticsearch9/dsl/update_by_query_base.py +149 -0
- elasticsearch9/dsl/utils.py +687 -0
- elasticsearch9/dsl/wrappers.py +144 -0
- elasticsearch9/exceptions.py +133 -0
- elasticsearch9/helpers/__init__.py +41 -0
- elasticsearch9/helpers/actions.py +875 -0
- elasticsearch9/helpers/errors.py +40 -0
- elasticsearch9/helpers/vectorstore/__init__.py +62 -0
- elasticsearch9/helpers/vectorstore/_async/__init__.py +16 -0
- elasticsearch9/helpers/vectorstore/_async/_utils.py +39 -0
- elasticsearch9/helpers/vectorstore/_async/embedding_service.py +89 -0
- elasticsearch9/helpers/vectorstore/_async/strategies.py +487 -0
- elasticsearch9/helpers/vectorstore/_async/vectorstore.py +421 -0
- elasticsearch9/helpers/vectorstore/_sync/__init__.py +16 -0
- elasticsearch9/helpers/vectorstore/_sync/_utils.py +39 -0
- elasticsearch9/helpers/vectorstore/_sync/embedding_service.py +89 -0
- elasticsearch9/helpers/vectorstore/_sync/strategies.py +487 -0
- elasticsearch9/helpers/vectorstore/_sync/vectorstore.py +421 -0
- elasticsearch9/helpers/vectorstore/_utils.py +116 -0
- elasticsearch9/py.typed +0 -0
- elasticsearch9/serializer.py +250 -0
- elasticsearch9-9.0.0.dist-info/METADATA +175 -0
- elasticsearch9-9.0.0.dist-info/RECORD +160 -0
- elasticsearch9-9.0.0.dist-info/WHEEL +4 -0
- elasticsearch9-9.0.0.dist-info/licenses/LICENSE +176 -0
- elasticsearch9-9.0.0.dist-info/licenses/NOTICE +2 -0
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
# Licensed to Elasticsearch B.V. under one or more contributor
|
|
2
|
+
# license agreements. See the NOTICE file distributed with
|
|
3
|
+
# this work for additional information regarding copyright
|
|
4
|
+
# ownership. Elasticsearch B.V. licenses this file to you under
|
|
5
|
+
# the Apache License, Version 2.0 (the "License"); you may
|
|
6
|
+
# not use this file except in compliance with the License.
|
|
7
|
+
# You may obtain a copy of the License at
|
|
8
|
+
#
|
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
#
|
|
11
|
+
# Unless required by applicable law or agreed to in writing,
|
|
12
|
+
# software distributed under the License is distributed on an
|
|
13
|
+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
14
|
+
# KIND, either express or implied. See the License for the
|
|
15
|
+
# specific language governing permissions and limitations
|
|
16
|
+
# under the License.
|
|
17
|
+
|
|
18
|
+
import re
|
|
19
|
+
import warnings
|
|
20
|
+
from typing import (
|
|
21
|
+
Any,
|
|
22
|
+
Callable,
|
|
23
|
+
Collection,
|
|
24
|
+
Dict,
|
|
25
|
+
Iterable,
|
|
26
|
+
List,
|
|
27
|
+
Mapping,
|
|
28
|
+
Optional,
|
|
29
|
+
Tuple,
|
|
30
|
+
Union,
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
from elastic_transport import (
|
|
34
|
+
ApiResponse,
|
|
35
|
+
AsyncTransport,
|
|
36
|
+
BinaryApiResponse,
|
|
37
|
+
HeadApiResponse,
|
|
38
|
+
HttpHeaders,
|
|
39
|
+
ListApiResponse,
|
|
40
|
+
NodeConfig,
|
|
41
|
+
ObjectApiResponse,
|
|
42
|
+
OpenTelemetrySpan,
|
|
43
|
+
SniffOptions,
|
|
44
|
+
TextApiResponse,
|
|
45
|
+
)
|
|
46
|
+
from elastic_transport.client_utils import DEFAULT, DefaultType
|
|
47
|
+
|
|
48
|
+
from ..._otel import OpenTelemetry
|
|
49
|
+
from ..._version import __versionstr__
|
|
50
|
+
from ...compat import warn_stacklevel
|
|
51
|
+
from ...exceptions import (
|
|
52
|
+
HTTP_EXCEPTIONS,
|
|
53
|
+
ApiError,
|
|
54
|
+
ConnectionError,
|
|
55
|
+
ElasticsearchWarning,
|
|
56
|
+
SerializationError,
|
|
57
|
+
UnsupportedProductError,
|
|
58
|
+
)
|
|
59
|
+
from .utils import _TYPE_ASYNC_SNIFF_CALLBACK, _base64_auth_header, _quote_query
|
|
60
|
+
|
|
61
|
+
_WARNING_RE = re.compile(r"\"([^\"]*)\"")
|
|
62
|
+
_COMPAT_MIMETYPE_TEMPLATE = "application/vnd.elasticsearch+%s; compatible-with=" + str(
|
|
63
|
+
__versionstr__.partition(".")[0]
|
|
64
|
+
)
|
|
65
|
+
_COMPAT_MIMETYPE_RE = re.compile(r"application/(json|x-ndjson|vnd\.mapbox-vector-tile)")
|
|
66
|
+
_COMPAT_MIMETYPE_SUB = _COMPAT_MIMETYPE_TEMPLATE % (r"\g<1>",)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def resolve_auth_headers(
|
|
70
|
+
headers: Optional[Mapping[str, str]],
|
|
71
|
+
http_auth: Union[DefaultType, None, Tuple[str, str], str] = DEFAULT,
|
|
72
|
+
api_key: Union[DefaultType, None, Tuple[str, str], str] = DEFAULT,
|
|
73
|
+
basic_auth: Union[DefaultType, None, Tuple[str, str], str] = DEFAULT,
|
|
74
|
+
bearer_auth: Union[DefaultType, None, str] = DEFAULT,
|
|
75
|
+
) -> HttpHeaders:
|
|
76
|
+
if headers is None:
|
|
77
|
+
headers = HttpHeaders()
|
|
78
|
+
elif not isinstance(headers, HttpHeaders):
|
|
79
|
+
headers = HttpHeaders(headers)
|
|
80
|
+
|
|
81
|
+
resolved_http_auth = http_auth if http_auth is not DEFAULT else None
|
|
82
|
+
resolved_basic_auth = basic_auth if basic_auth is not DEFAULT else None
|
|
83
|
+
if resolved_http_auth is not None:
|
|
84
|
+
if resolved_basic_auth is not None:
|
|
85
|
+
raise ValueError(
|
|
86
|
+
"Can't specify both 'http_auth' and 'basic_auth', "
|
|
87
|
+
"instead only specify 'basic_auth'"
|
|
88
|
+
)
|
|
89
|
+
if isinstance(http_auth, str) or (
|
|
90
|
+
isinstance(resolved_http_auth, (list, tuple))
|
|
91
|
+
and all(isinstance(x, str) for x in resolved_http_auth)
|
|
92
|
+
):
|
|
93
|
+
resolved_basic_auth = resolved_http_auth
|
|
94
|
+
else:
|
|
95
|
+
raise TypeError(
|
|
96
|
+
"The deprecated 'http_auth' parameter must be either 'Tuple[str, str]' or 'str'. "
|
|
97
|
+
"Use either the 'basic_auth' parameter instead"
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
warnings.warn(
|
|
101
|
+
"The 'http_auth' parameter is deprecated. "
|
|
102
|
+
"Use 'basic_auth' or 'bearer_auth' parameters instead",
|
|
103
|
+
category=DeprecationWarning,
|
|
104
|
+
stacklevel=warn_stacklevel(),
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
resolved_api_key = api_key if api_key is not DEFAULT else None
|
|
108
|
+
resolved_bearer_auth = bearer_auth if bearer_auth is not DEFAULT else None
|
|
109
|
+
if resolved_api_key or resolved_basic_auth or resolved_bearer_auth:
|
|
110
|
+
if (
|
|
111
|
+
sum(
|
|
112
|
+
x is not None
|
|
113
|
+
for x in (
|
|
114
|
+
resolved_api_key,
|
|
115
|
+
resolved_basic_auth,
|
|
116
|
+
resolved_bearer_auth,
|
|
117
|
+
)
|
|
118
|
+
)
|
|
119
|
+
> 1
|
|
120
|
+
):
|
|
121
|
+
raise ValueError(
|
|
122
|
+
"Can only set one of 'api_key', 'basic_auth', and 'bearer_auth'"
|
|
123
|
+
)
|
|
124
|
+
if headers and headers.get("authorization", None) is not None:
|
|
125
|
+
raise ValueError(
|
|
126
|
+
"Can't set 'Authorization' HTTP header with other authentication options"
|
|
127
|
+
)
|
|
128
|
+
if resolved_api_key:
|
|
129
|
+
headers["authorization"] = f"ApiKey {_base64_auth_header(resolved_api_key)}"
|
|
130
|
+
if resolved_basic_auth:
|
|
131
|
+
headers["authorization"] = (
|
|
132
|
+
f"Basic {_base64_auth_header(resolved_basic_auth)}"
|
|
133
|
+
)
|
|
134
|
+
if resolved_bearer_auth:
|
|
135
|
+
headers["authorization"] = f"Bearer {resolved_bearer_auth}"
|
|
136
|
+
|
|
137
|
+
return headers
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def create_sniff_callback(
|
|
141
|
+
host_info_callback: Optional[
|
|
142
|
+
Callable[[Dict[str, Any], Dict[str, Any]], Optional[Dict[str, Any]]]
|
|
143
|
+
] = None,
|
|
144
|
+
sniffed_node_callback: Optional[
|
|
145
|
+
Callable[[Dict[str, Any], NodeConfig], Optional[NodeConfig]]
|
|
146
|
+
] = None,
|
|
147
|
+
) -> _TYPE_ASYNC_SNIFF_CALLBACK:
|
|
148
|
+
assert (host_info_callback is None) != (sniffed_node_callback is None)
|
|
149
|
+
|
|
150
|
+
# Wrap the deprecated 'host_info_callback' into 'sniffed_node_callback'
|
|
151
|
+
if host_info_callback is not None:
|
|
152
|
+
|
|
153
|
+
def _sniffed_node_callback(
|
|
154
|
+
node_info: Dict[str, Any], node_config: NodeConfig
|
|
155
|
+
) -> Optional[NodeConfig]:
|
|
156
|
+
assert host_info_callback is not None
|
|
157
|
+
if (
|
|
158
|
+
host_info_callback( # type ignore[misc]
|
|
159
|
+
node_info, {"host": node_config.host, "port": node_config.port}
|
|
160
|
+
)
|
|
161
|
+
is None
|
|
162
|
+
):
|
|
163
|
+
return None
|
|
164
|
+
return node_config
|
|
165
|
+
|
|
166
|
+
sniffed_node_callback = _sniffed_node_callback
|
|
167
|
+
|
|
168
|
+
async def sniff_callback(
|
|
169
|
+
transport: AsyncTransport, sniff_options: SniffOptions
|
|
170
|
+
) -> List[NodeConfig]:
|
|
171
|
+
for _ in transport.node_pool.all():
|
|
172
|
+
try:
|
|
173
|
+
meta, node_infos = await transport.perform_request(
|
|
174
|
+
"GET",
|
|
175
|
+
"/_nodes/_all/http",
|
|
176
|
+
headers={
|
|
177
|
+
"accept": "application/vnd.elasticsearch+json; compatible-with=9"
|
|
178
|
+
},
|
|
179
|
+
request_timeout=(
|
|
180
|
+
sniff_options.sniff_timeout
|
|
181
|
+
if not sniff_options.is_initial_sniff
|
|
182
|
+
else None
|
|
183
|
+
),
|
|
184
|
+
)
|
|
185
|
+
except (SerializationError, ConnectionError):
|
|
186
|
+
continue
|
|
187
|
+
|
|
188
|
+
if not 200 <= meta.status <= 299:
|
|
189
|
+
continue
|
|
190
|
+
|
|
191
|
+
node_configs = []
|
|
192
|
+
for node_info in node_infos.get("nodes", {}).values():
|
|
193
|
+
address = node_info.get("http", {}).get("publish_address")
|
|
194
|
+
if not address or ":" not in address:
|
|
195
|
+
continue
|
|
196
|
+
|
|
197
|
+
if "/" in address:
|
|
198
|
+
# Support 7.x host/ip:port behavior where http.publish_host has been set.
|
|
199
|
+
fqdn, ipaddress = address.split("/", 1)
|
|
200
|
+
host = fqdn
|
|
201
|
+
_, port_str = ipaddress.rsplit(":", 1)
|
|
202
|
+
port = int(port_str)
|
|
203
|
+
else:
|
|
204
|
+
host, port_str = address.rsplit(":", 1)
|
|
205
|
+
port = int(port_str)
|
|
206
|
+
|
|
207
|
+
assert sniffed_node_callback is not None
|
|
208
|
+
sniffed_node = sniffed_node_callback(
|
|
209
|
+
node_info, meta.node.replace(host=host, port=port)
|
|
210
|
+
)
|
|
211
|
+
if sniffed_node is None:
|
|
212
|
+
continue
|
|
213
|
+
|
|
214
|
+
# Use the node which was able to make the request as a base.
|
|
215
|
+
node_configs.append(sniffed_node)
|
|
216
|
+
|
|
217
|
+
if node_configs:
|
|
218
|
+
return node_configs
|
|
219
|
+
|
|
220
|
+
return []
|
|
221
|
+
|
|
222
|
+
return sniff_callback
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def _default_sniffed_node_callback(
|
|
226
|
+
node_info: Dict[str, Any], node_config: NodeConfig
|
|
227
|
+
) -> Optional[NodeConfig]:
|
|
228
|
+
if node_info.get("roles", []) == ["master"]:
|
|
229
|
+
return None
|
|
230
|
+
return node_config
|
|
231
|
+
|
|
232
|
+
|
|
233
|
+
default_sniff_callback = create_sniff_callback(
|
|
234
|
+
sniffed_node_callback=_default_sniffed_node_callback
|
|
235
|
+
)
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
class BaseClient:
|
|
239
|
+
def __init__(self, _transport: AsyncTransport) -> None:
|
|
240
|
+
self._transport = _transport
|
|
241
|
+
self._client_meta: Union[DefaultType, Tuple[Tuple[str, str], ...]] = DEFAULT
|
|
242
|
+
self._headers = HttpHeaders()
|
|
243
|
+
self._request_timeout: Union[DefaultType, Optional[float]] = DEFAULT
|
|
244
|
+
self._ignore_status: Union[DefaultType, Collection[int]] = DEFAULT
|
|
245
|
+
self._max_retries: Union[DefaultType, int] = DEFAULT
|
|
246
|
+
self._retry_on_timeout: Union[DefaultType, bool] = DEFAULT
|
|
247
|
+
self._retry_on_status: Union[DefaultType, Collection[int]] = DEFAULT
|
|
248
|
+
self._verified_elasticsearch = False
|
|
249
|
+
self._otel = OpenTelemetry()
|
|
250
|
+
|
|
251
|
+
@property
|
|
252
|
+
def transport(self) -> AsyncTransport:
|
|
253
|
+
return self._transport
|
|
254
|
+
|
|
255
|
+
async def perform_request(
|
|
256
|
+
self,
|
|
257
|
+
method: str,
|
|
258
|
+
path: str,
|
|
259
|
+
*,
|
|
260
|
+
params: Optional[Mapping[str, Any]] = None,
|
|
261
|
+
headers: Optional[Mapping[str, str]] = None,
|
|
262
|
+
body: Optional[Any] = None,
|
|
263
|
+
endpoint_id: Optional[str] = None,
|
|
264
|
+
path_parts: Optional[Mapping[str, Any]] = None,
|
|
265
|
+
) -> ApiResponse[Any]:
|
|
266
|
+
with self._otel.span(
|
|
267
|
+
method,
|
|
268
|
+
endpoint_id=endpoint_id,
|
|
269
|
+
path_parts=path_parts or {},
|
|
270
|
+
) as otel_span:
|
|
271
|
+
response = await self._perform_request(
|
|
272
|
+
method,
|
|
273
|
+
path,
|
|
274
|
+
params=params,
|
|
275
|
+
headers=headers,
|
|
276
|
+
body=body,
|
|
277
|
+
otel_span=otel_span,
|
|
278
|
+
)
|
|
279
|
+
otel_span.set_elastic_cloud_metadata(response.meta.headers)
|
|
280
|
+
return response
|
|
281
|
+
|
|
282
|
+
async def _perform_request(
|
|
283
|
+
self,
|
|
284
|
+
method: str,
|
|
285
|
+
path: str,
|
|
286
|
+
*,
|
|
287
|
+
params: Optional[Mapping[str, Any]] = None,
|
|
288
|
+
headers: Optional[Mapping[str, str]] = None,
|
|
289
|
+
body: Optional[Any] = None,
|
|
290
|
+
otel_span: OpenTelemetrySpan,
|
|
291
|
+
) -> ApiResponse[Any]:
|
|
292
|
+
if headers:
|
|
293
|
+
request_headers = self._headers.copy()
|
|
294
|
+
request_headers.update(headers)
|
|
295
|
+
else:
|
|
296
|
+
request_headers = self._headers
|
|
297
|
+
|
|
298
|
+
def mimetype_header_to_compat(header: str) -> None:
|
|
299
|
+
# Converts all parts of a Accept/Content-Type headers
|
|
300
|
+
# from application/X -> application/vnd.elasticsearch+X
|
|
301
|
+
mimetype = request_headers.get(header, None)
|
|
302
|
+
if mimetype:
|
|
303
|
+
request_headers[header] = _COMPAT_MIMETYPE_RE.sub(
|
|
304
|
+
_COMPAT_MIMETYPE_SUB, mimetype
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
mimetype_header_to_compat("Accept")
|
|
308
|
+
mimetype_header_to_compat("Content-Type")
|
|
309
|
+
|
|
310
|
+
if params:
|
|
311
|
+
target = f"{path}?{_quote_query(params)}"
|
|
312
|
+
else:
|
|
313
|
+
target = path
|
|
314
|
+
|
|
315
|
+
meta, resp_body = await self.transport.perform_request(
|
|
316
|
+
method,
|
|
317
|
+
target,
|
|
318
|
+
headers=request_headers,
|
|
319
|
+
body=body,
|
|
320
|
+
request_timeout=self._request_timeout,
|
|
321
|
+
max_retries=self._max_retries,
|
|
322
|
+
retry_on_status=self._retry_on_status,
|
|
323
|
+
retry_on_timeout=self._retry_on_timeout,
|
|
324
|
+
client_meta=self._client_meta,
|
|
325
|
+
otel_span=otel_span,
|
|
326
|
+
)
|
|
327
|
+
|
|
328
|
+
# HEAD with a 404 is returned as a normal response
|
|
329
|
+
# since this is used as an 'exists' functionality.
|
|
330
|
+
if not (method == "HEAD" and meta.status == 404) and (
|
|
331
|
+
not 200 <= meta.status < 299
|
|
332
|
+
and (
|
|
333
|
+
self._ignore_status is DEFAULT
|
|
334
|
+
or self._ignore_status is None
|
|
335
|
+
or meta.status not in self._ignore_status
|
|
336
|
+
)
|
|
337
|
+
):
|
|
338
|
+
message = str(resp_body)
|
|
339
|
+
|
|
340
|
+
# If the response is an error response try parsing
|
|
341
|
+
# the raw Elasticsearch error before raising.
|
|
342
|
+
if isinstance(resp_body, dict):
|
|
343
|
+
try:
|
|
344
|
+
error = resp_body.get("error", message)
|
|
345
|
+
if isinstance(error, dict) and "type" in error:
|
|
346
|
+
error = error["type"]
|
|
347
|
+
message = error
|
|
348
|
+
except (ValueError, KeyError, TypeError):
|
|
349
|
+
pass
|
|
350
|
+
|
|
351
|
+
raise HTTP_EXCEPTIONS.get(meta.status, ApiError)(
|
|
352
|
+
message=message, meta=meta, body=resp_body
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
# 'X-Elastic-Product: Elasticsearch' should be on every 2XX response.
|
|
356
|
+
if not self._verified_elasticsearch:
|
|
357
|
+
# If the header is set we mark the server as verified.
|
|
358
|
+
if meta.headers.get("x-elastic-product", "") == "Elasticsearch":
|
|
359
|
+
self._verified_elasticsearch = True
|
|
360
|
+
# Otherwise we only raise an error on 2XX responses.
|
|
361
|
+
elif meta.status >= 200 and meta.status < 300:
|
|
362
|
+
raise UnsupportedProductError(
|
|
363
|
+
message=(
|
|
364
|
+
"The client noticed that the server is not Elasticsearch "
|
|
365
|
+
"and we do not support this unknown product"
|
|
366
|
+
),
|
|
367
|
+
meta=meta,
|
|
368
|
+
body=resp_body,
|
|
369
|
+
)
|
|
370
|
+
|
|
371
|
+
# 'Warning' headers should be reraised as 'ElasticsearchWarning'
|
|
372
|
+
if "warning" in meta.headers:
|
|
373
|
+
warning_header = (meta.headers.get("warning") or "").strip()
|
|
374
|
+
warning_messages: Iterable[str] = _WARNING_RE.findall(warning_header) or (
|
|
375
|
+
warning_header,
|
|
376
|
+
)
|
|
377
|
+
stacklevel = warn_stacklevel()
|
|
378
|
+
for warning_message in warning_messages:
|
|
379
|
+
warnings.warn(
|
|
380
|
+
warning_message,
|
|
381
|
+
category=ElasticsearchWarning,
|
|
382
|
+
stacklevel=stacklevel,
|
|
383
|
+
)
|
|
384
|
+
|
|
385
|
+
if method == "HEAD":
|
|
386
|
+
response = HeadApiResponse(meta=meta)
|
|
387
|
+
elif isinstance(resp_body, dict):
|
|
388
|
+
response = ObjectApiResponse(body=resp_body, meta=meta) # type: ignore[assignment]
|
|
389
|
+
elif isinstance(resp_body, list):
|
|
390
|
+
response = ListApiResponse(body=resp_body, meta=meta) # type: ignore[assignment]
|
|
391
|
+
elif isinstance(resp_body, str):
|
|
392
|
+
response = TextApiResponse( # type: ignore[assignment]
|
|
393
|
+
body=resp_body,
|
|
394
|
+
meta=meta,
|
|
395
|
+
)
|
|
396
|
+
elif isinstance(resp_body, bytes):
|
|
397
|
+
response = BinaryApiResponse(body=resp_body, meta=meta) # type: ignore[assignment]
|
|
398
|
+
else:
|
|
399
|
+
response = ApiResponse(body=resp_body, meta=meta) # type: ignore[assignment]
|
|
400
|
+
|
|
401
|
+
return response
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
class NamespacedClient(BaseClient):
|
|
405
|
+
def __init__(self, client: "BaseClient") -> None:
|
|
406
|
+
self._client = client
|
|
407
|
+
super().__init__(self._client.transport)
|
|
408
|
+
|
|
409
|
+
async def perform_request(
|
|
410
|
+
self,
|
|
411
|
+
method: str,
|
|
412
|
+
path: str,
|
|
413
|
+
*,
|
|
414
|
+
params: Optional[Mapping[str, Any]] = None,
|
|
415
|
+
headers: Optional[Mapping[str, str]] = None,
|
|
416
|
+
body: Optional[Any] = None,
|
|
417
|
+
endpoint_id: Optional[str] = None,
|
|
418
|
+
path_parts: Optional[Mapping[str, Any]] = None,
|
|
419
|
+
) -> ApiResponse[Any]:
|
|
420
|
+
# Use the internal clients .perform_request() implementation
|
|
421
|
+
# so we take advantage of their transport options.
|
|
422
|
+
return await self._client.perform_request(
|
|
423
|
+
method,
|
|
424
|
+
path,
|
|
425
|
+
params=params,
|
|
426
|
+
headers=headers,
|
|
427
|
+
body=body,
|
|
428
|
+
endpoint_id=endpoint_id,
|
|
429
|
+
path_parts=path_parts,
|
|
430
|
+
)
|