hermes-client-python 1.8.40__tar.gz → 1.8.43__tar.gz
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.
- {hermes_client_python-1.8.40 → hermes_client_python-1.8.43}/PKG-INFO +13 -1
- {hermes_client_python-1.8.40 → hermes_client_python-1.8.43}/README.md +12 -0
- {hermes_client_python-1.8.40 → hermes_client_python-1.8.43}/pyproject.toml +1 -1
- {hermes_client_python-1.8.40 → hermes_client_python-1.8.43}/src/hermes_client_python/client.py +86 -26
- {hermes_client_python-1.8.40 → hermes_client_python-1.8.43}/.gitignore +0 -0
- {hermes_client_python-1.8.40 → hermes_client_python-1.8.43}/src/hermes_client_python/__init__.py +0 -0
- {hermes_client_python-1.8.40 → hermes_client_python-1.8.43}/src/hermes_client_python/hermes_pb2.py +0 -0
- {hermes_client_python-1.8.40 → hermes_client_python-1.8.43}/src/hermes_client_python/hermes_pb2_grpc.py +0 -0
- {hermes_client_python-1.8.40 → hermes_client_python-1.8.43}/src/hermes_client_python/types.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hermes-client-python
|
|
3
|
-
Version: 1.8.
|
|
3
|
+
Version: 1.8.43
|
|
4
4
|
Summary: Async Python client for Hermes search server
|
|
5
5
|
Project-URL: Homepage, https://github.com/SpaceFrontiers/hermes
|
|
6
6
|
Project-URL: Repository, https://github.com/SpaceFrontiers/hermes
|
|
@@ -230,3 +230,15 @@ python generate_proto.py
|
|
|
230
230
|
## License
|
|
231
231
|
|
|
232
232
|
MIT
|
|
233
|
+
|
|
234
|
+
## Timeouts / deadlines
|
|
235
|
+
|
|
236
|
+
Every RPC accepts an optional `timeout` (seconds) which sets a gRPC deadline;
|
|
237
|
+
a client-wide default can be set in the constructor. On expiry the call
|
|
238
|
+
raises `grpc.aio.AioRpcError` with `DEADLINE_EXCEEDED`.
|
|
239
|
+
|
|
240
|
+
```python
|
|
241
|
+
client = HermesClient("localhost:50051", default_timeout=5.0)
|
|
242
|
+
results = await client.search("articles", query={...}, timeout=0.5) # per-call override
|
|
243
|
+
await client.force_merge("articles", timeout=3600) # long op, long deadline
|
|
244
|
+
```
|
|
@@ -206,3 +206,15 @@ python generate_proto.py
|
|
|
206
206
|
## License
|
|
207
207
|
|
|
208
208
|
MIT
|
|
209
|
+
|
|
210
|
+
## Timeouts / deadlines
|
|
211
|
+
|
|
212
|
+
Every RPC accepts an optional `timeout` (seconds) which sets a gRPC deadline;
|
|
213
|
+
a client-wide default can be set in the constructor. On expiry the call
|
|
214
|
+
raises `grpc.aio.AioRpcError` with `DEADLINE_EXCEEDED`.
|
|
215
|
+
|
|
216
|
+
```python
|
|
217
|
+
client = HermesClient("localhost:50051", default_timeout=5.0)
|
|
218
|
+
results = await client.search("articles", query={...}, timeout=0.5) # per-call override
|
|
219
|
+
await client.force_merge("articles", timeout=3600) # long op, long deadline
|
|
220
|
+
```
|
{hermes_client_python-1.8.40 → hermes_client_python-1.8.43}/src/hermes_client_python/client.py
RENAMED
|
@@ -56,17 +56,31 @@ class HermesClient:
|
|
|
56
56
|
print(hit.address, hit.score)
|
|
57
57
|
"""
|
|
58
58
|
|
|
59
|
-
def __init__(
|
|
59
|
+
def __init__(
|
|
60
|
+
self,
|
|
61
|
+
address: str = "localhost:50051",
|
|
62
|
+
default_timeout: float | None = None,
|
|
63
|
+
):
|
|
60
64
|
"""Initialize client.
|
|
61
65
|
|
|
62
66
|
Args:
|
|
63
67
|
address: Server address in format "host:port"
|
|
68
|
+
default_timeout: Default per-RPC deadline in seconds, applied to
|
|
69
|
+
every call unless overridden by the call's ``timeout=``
|
|
70
|
+
argument. ``None`` = no deadline (current behaviour). On
|
|
71
|
+
expiry the call raises ``grpc.aio.AioRpcError`` with
|
|
72
|
+
``DEADLINE_EXCEEDED``.
|
|
64
73
|
"""
|
|
65
74
|
self.address = address
|
|
75
|
+
self.default_timeout = default_timeout
|
|
66
76
|
self._channel: aio.Channel | None = None
|
|
67
77
|
self._index_stub: pb_grpc.IndexServiceStub | None = None
|
|
68
78
|
self._search_stub: pb_grpc.SearchServiceStub | None = None
|
|
69
79
|
|
|
80
|
+
def _deadline(self, timeout: float | None) -> float | None:
|
|
81
|
+
"""Effective per-call gRPC deadline in seconds."""
|
|
82
|
+
return timeout if timeout is not None else self.default_timeout
|
|
83
|
+
|
|
70
84
|
async def connect(self) -> None:
|
|
71
85
|
"""Connect to the server."""
|
|
72
86
|
# Increase message size limits for large responses (e.g., loading content fields)
|
|
@@ -108,7 +122,9 @@ class HermesClient:
|
|
|
108
122
|
# Index Management
|
|
109
123
|
# =========================================================================
|
|
110
124
|
|
|
111
|
-
async def create_index(
|
|
125
|
+
async def create_index(
|
|
126
|
+
self, index_name: str, schema: str, timeout: float | None = None
|
|
127
|
+
) -> bool:
|
|
112
128
|
"""Create a new index.
|
|
113
129
|
|
|
114
130
|
Args:
|
|
@@ -134,10 +150,12 @@ class HermesClient:
|
|
|
134
150
|
"""
|
|
135
151
|
self._ensure_connected()
|
|
136
152
|
request = pb.CreateIndexRequest(index_name=index_name, schema=schema)
|
|
137
|
-
response = await self._index_stub.CreateIndex(
|
|
153
|
+
response = await self._index_stub.CreateIndex(
|
|
154
|
+
request, timeout=self._deadline(timeout)
|
|
155
|
+
)
|
|
138
156
|
return response.success
|
|
139
157
|
|
|
140
|
-
async def delete_index(self, index_name: str) -> bool:
|
|
158
|
+
async def delete_index(self, index_name: str, timeout: float | None = None) -> bool:
|
|
141
159
|
"""Delete an index.
|
|
142
160
|
|
|
143
161
|
Args:
|
|
@@ -148,10 +166,12 @@ class HermesClient:
|
|
|
148
166
|
"""
|
|
149
167
|
self._ensure_connected()
|
|
150
168
|
request = pb.DeleteIndexRequest(index_name=index_name)
|
|
151
|
-
response = await self._index_stub.DeleteIndex(
|
|
169
|
+
response = await self._index_stub.DeleteIndex(
|
|
170
|
+
request, timeout=self._deadline(timeout)
|
|
171
|
+
)
|
|
152
172
|
return response.success
|
|
153
173
|
|
|
154
|
-
async def list_indexes(self) -> list[str]:
|
|
174
|
+
async def list_indexes(self, timeout: float | None = None) -> list[str]:
|
|
155
175
|
"""List all indexes on the server.
|
|
156
176
|
|
|
157
177
|
Returns:
|
|
@@ -159,10 +179,14 @@ class HermesClient:
|
|
|
159
179
|
"""
|
|
160
180
|
self._ensure_connected()
|
|
161
181
|
request = pb.ListIndexesRequest()
|
|
162
|
-
response = await self._index_stub.ListIndexes(
|
|
182
|
+
response = await self._index_stub.ListIndexes(
|
|
183
|
+
request, timeout=self._deadline(timeout)
|
|
184
|
+
)
|
|
163
185
|
return list(response.index_names)
|
|
164
186
|
|
|
165
|
-
async def get_index_info(
|
|
187
|
+
async def get_index_info(
|
|
188
|
+
self, index_name: str, timeout: float | None = None
|
|
189
|
+
) -> IndexInfo:
|
|
166
190
|
"""Get information about an index.
|
|
167
191
|
|
|
168
192
|
Args:
|
|
@@ -173,7 +197,9 @@ class HermesClient:
|
|
|
173
197
|
"""
|
|
174
198
|
self._ensure_connected()
|
|
175
199
|
request = pb.GetIndexInfoRequest(index_name=index_name)
|
|
176
|
-
response = await self._search_stub.GetIndexInfo(
|
|
200
|
+
response = await self._search_stub.GetIndexInfo(
|
|
201
|
+
request, timeout=self._deadline(timeout)
|
|
202
|
+
)
|
|
177
203
|
vector_stats = [
|
|
178
204
|
VectorFieldStats(
|
|
179
205
|
field_name=vs.field_name,
|
|
@@ -196,7 +222,10 @@ class HermesClient:
|
|
|
196
222
|
# =========================================================================
|
|
197
223
|
|
|
198
224
|
async def index_documents(
|
|
199
|
-
self,
|
|
225
|
+
self,
|
|
226
|
+
index_name: str,
|
|
227
|
+
documents: list[dict[str, Any]],
|
|
228
|
+
timeout: float | None = None,
|
|
200
229
|
) -> tuple[int, int, list[dict[str, Any]]]:
|
|
201
230
|
"""Index multiple documents in batch.
|
|
202
231
|
|
|
@@ -218,21 +247,32 @@ class HermesClient:
|
|
|
218
247
|
request = pb.BatchIndexDocumentsRequest(
|
|
219
248
|
index_name=index_name, documents=named_docs
|
|
220
249
|
)
|
|
221
|
-
response = await self._index_stub.BatchIndexDocuments(
|
|
250
|
+
response = await self._index_stub.BatchIndexDocuments(
|
|
251
|
+
request, timeout=self._deadline(timeout)
|
|
252
|
+
)
|
|
222
253
|
errors = [{"index": e.index, "error": e.error} for e in response.errors]
|
|
223
254
|
return response.indexed_count, response.error_count, errors
|
|
224
255
|
|
|
225
|
-
async def index_document(
|
|
256
|
+
async def index_document(
|
|
257
|
+
self,
|
|
258
|
+
index_name: str,
|
|
259
|
+
document: dict[str, Any],
|
|
260
|
+
timeout: float | None = None,
|
|
261
|
+
) -> None:
|
|
226
262
|
"""Index a single document.
|
|
227
263
|
|
|
228
264
|
Args:
|
|
229
265
|
index_name: Name of the index
|
|
230
266
|
document: Document as dict with field names as keys
|
|
267
|
+
timeout: Per-call deadline in seconds (overrides ``default_timeout``)
|
|
231
268
|
"""
|
|
232
|
-
await self.index_documents(index_name, [document])
|
|
269
|
+
await self.index_documents(index_name, [document], timeout=timeout)
|
|
233
270
|
|
|
234
271
|
async def index_documents_stream(
|
|
235
|
-
self,
|
|
272
|
+
self,
|
|
273
|
+
index_name: str,
|
|
274
|
+
documents: AsyncIterator[dict[str, Any]],
|
|
275
|
+
timeout: float | None = None,
|
|
236
276
|
) -> tuple[int, list[dict[str, Any]]]:
|
|
237
277
|
"""Stream documents for indexing.
|
|
238
278
|
|
|
@@ -251,11 +291,13 @@ class HermesClient:
|
|
|
251
291
|
fields = _to_field_entries(doc)
|
|
252
292
|
yield pb.IndexDocumentRequest(index_name=index_name, fields=fields)
|
|
253
293
|
|
|
254
|
-
response = await self._index_stub.IndexDocuments(
|
|
294
|
+
response = await self._index_stub.IndexDocuments(
|
|
295
|
+
request_iterator(), timeout=self._deadline(timeout)
|
|
296
|
+
)
|
|
255
297
|
errors = [{"index": e.index, "error": e.error} for e in response.errors]
|
|
256
298
|
return response.indexed_count, errors
|
|
257
299
|
|
|
258
|
-
async def commit(self, index_name: str) -> int:
|
|
300
|
+
async def commit(self, index_name: str, timeout: float | None = None) -> int:
|
|
259
301
|
"""Commit pending changes.
|
|
260
302
|
|
|
261
303
|
Args:
|
|
@@ -266,10 +308,12 @@ class HermesClient:
|
|
|
266
308
|
"""
|
|
267
309
|
self._ensure_connected()
|
|
268
310
|
request = pb.CommitRequest(index_name=index_name)
|
|
269
|
-
response = await self._index_stub.Commit(
|
|
311
|
+
response = await self._index_stub.Commit(
|
|
312
|
+
request, timeout=self._deadline(timeout)
|
|
313
|
+
)
|
|
270
314
|
return response.num_docs
|
|
271
315
|
|
|
272
|
-
async def force_merge(self, index_name: str) -> int:
|
|
316
|
+
async def force_merge(self, index_name: str, timeout: float | None = None) -> int:
|
|
273
317
|
"""Force merge all segments.
|
|
274
318
|
|
|
275
319
|
Args:
|
|
@@ -280,10 +324,12 @@ class HermesClient:
|
|
|
280
324
|
"""
|
|
281
325
|
self._ensure_connected()
|
|
282
326
|
request = pb.ForceMergeRequest(index_name=index_name)
|
|
283
|
-
response = await self._index_stub.ForceMerge(
|
|
327
|
+
response = await self._index_stub.ForceMerge(
|
|
328
|
+
request, timeout=self._deadline(timeout)
|
|
329
|
+
)
|
|
284
330
|
return response.num_segments
|
|
285
331
|
|
|
286
|
-
async def reorder(self, index_name: str) -> int:
|
|
332
|
+
async def reorder(self, index_name: str, timeout: float | None = None) -> int:
|
|
287
333
|
"""Reorder BMP blocks by SimHash similarity for better pruning.
|
|
288
334
|
|
|
289
335
|
Performs record-level reordering: shuffles individual ordinals across
|
|
@@ -298,10 +344,14 @@ class HermesClient:
|
|
|
298
344
|
"""
|
|
299
345
|
self._ensure_connected()
|
|
300
346
|
request = pb.ReorderRequest(index_name=index_name)
|
|
301
|
-
response = await self._index_stub.Reorder(
|
|
347
|
+
response = await self._index_stub.Reorder(
|
|
348
|
+
request, timeout=self._deadline(timeout)
|
|
349
|
+
)
|
|
302
350
|
return response.num_segments
|
|
303
351
|
|
|
304
|
-
async def retrain_vector_index(
|
|
352
|
+
async def retrain_vector_index(
|
|
353
|
+
self, index_name: str, timeout: float | None = None
|
|
354
|
+
) -> bool:
|
|
305
355
|
"""Retrain vector index centroids/codebooks from current data.
|
|
306
356
|
|
|
307
357
|
Resets the trained ANN structures and rebuilds them from scratch.
|
|
@@ -316,7 +366,9 @@ class HermesClient:
|
|
|
316
366
|
"""
|
|
317
367
|
self._ensure_connected()
|
|
318
368
|
request = pb.RetrainVectorIndexRequest(index_name=index_name)
|
|
319
|
-
response = await self._index_stub.RetrainVectorIndex(
|
|
369
|
+
response = await self._index_stub.RetrainVectorIndex(
|
|
370
|
+
request, timeout=self._deadline(timeout)
|
|
371
|
+
)
|
|
320
372
|
return response.success
|
|
321
373
|
|
|
322
374
|
# =========================================================================
|
|
@@ -332,6 +384,7 @@ class HermesClient:
|
|
|
332
384
|
offset: int = 0,
|
|
333
385
|
fields_to_load: list[str] | None = None,
|
|
334
386
|
reranker: dict[str, Any] | None = None,
|
|
387
|
+
timeout: float | None = None,
|
|
335
388
|
) -> SearchResponse:
|
|
336
389
|
"""Search for documents.
|
|
337
390
|
|
|
@@ -416,7 +469,9 @@ class HermesClient:
|
|
|
416
469
|
reranker=pb_reranker,
|
|
417
470
|
)
|
|
418
471
|
|
|
419
|
-
response = await self._search_stub.Search(
|
|
472
|
+
response = await self._search_stub.Search(
|
|
473
|
+
request, timeout=self._deadline(timeout)
|
|
474
|
+
)
|
|
420
475
|
|
|
421
476
|
hits = [
|
|
422
477
|
SearchHit(
|
|
@@ -452,7 +507,10 @@ class HermesClient:
|
|
|
452
507
|
)
|
|
453
508
|
|
|
454
509
|
async def get_document(
|
|
455
|
-
self,
|
|
510
|
+
self,
|
|
511
|
+
index_name: str,
|
|
512
|
+
address: DocAddress,
|
|
513
|
+
timeout: float | None = None,
|
|
456
514
|
) -> Document | None:
|
|
457
515
|
"""Get a document by address.
|
|
458
516
|
|
|
@@ -469,7 +527,9 @@ class HermesClient:
|
|
|
469
527
|
address=pb.DocAddress(segment_id=address.segment_id, doc_id=address.doc_id),
|
|
470
528
|
)
|
|
471
529
|
try:
|
|
472
|
-
response = await self._search_stub.GetDocument(
|
|
530
|
+
response = await self._search_stub.GetDocument(
|
|
531
|
+
request, timeout=self._deadline(timeout)
|
|
532
|
+
)
|
|
473
533
|
fields = {k: _from_field_value_list(v) for k, v in response.fields.items()}
|
|
474
534
|
return Document(fields=fields)
|
|
475
535
|
except grpc.RpcError as e:
|
|
File without changes
|
{hermes_client_python-1.8.40 → hermes_client_python-1.8.43}/src/hermes_client_python/__init__.py
RENAMED
|
File without changes
|
{hermes_client_python-1.8.40 → hermes_client_python-1.8.43}/src/hermes_client_python/hermes_pb2.py
RENAMED
|
File without changes
|
|
File without changes
|
{hermes_client_python-1.8.40 → hermes_client_python-1.8.43}/src/hermes_client_python/types.py
RENAMED
|
File without changes
|