hermes-client-python 1.8.41__py3-none-any.whl → 1.8.44__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.
@@ -56,17 +56,31 @@ class HermesClient:
56
56
  print(hit.address, hit.score)
57
57
  """
58
58
 
59
- def __init__(self, address: str = "localhost:50051"):
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(self, index_name: str, schema: str) -> bool:
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(request)
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(request)
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(request)
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(self, index_name: str) -> IndexInfo:
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(request)
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, index_name: str, documents: list[dict[str, Any]]
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(request)
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(self, index_name: str, document: dict[str, Any]) -> None:
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, index_name: str, documents: AsyncIterator[dict[str, Any]]
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(request_iterator())
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(request)
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(request)
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(request)
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(self, index_name: str) -> bool:
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(request)
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(request)
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, index_name: str, address: DocAddress
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(request)
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:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hermes-client-python
3
- Version: 1.8.41
3
+ Version: 1.8.44
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
+ ```
@@ -1,8 +1,8 @@
1
1
  hermes_client_python/__init__.py,sha256=sP0OZbXyYrLS3VMGGKZxZJZ4_GarUR5xlva3xzuh3t4,875
2
- hermes_client_python/client.py,sha256=d69J8_i2_xWfT0YpL83jV6UClxS8IaAhkMe6orURU4Y,29337
2
+ hermes_client_python/client.py,sha256=OqPxUzsuwUZixTJFkEkJAJSpcQmw8uD-JaIlbYL78EU,31300
3
3
  hermes_client_python/hermes_pb2.py,sha256=u0dYM2glIV2i-AF6RGvr3jEQaaiiCP1JhWWNu9DtLNI,19423
4
4
  hermes_client_python/hermes_pb2_grpc.py,sha256=5GEH_EtPe4fSljPJPwIt-aTGe_C9srOmpfYQ8NwO2YE,22605
5
5
  hermes_client_python/types.py,sha256=8itYT9epc1QVMvJRHeHHUOIxSBRAJySfhEDyYSNL5lA,4896
6
- hermes_client_python-1.8.41.dist-info/METADATA,sha256=YOSP-1g2BtpdRP4PsUbUh_0ORxfrJCrdzypcaKul2_8,6165
7
- hermes_client_python-1.8.41.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
8
- hermes_client_python-1.8.41.dist-info/RECORD,,
6
+ hermes_client_python-1.8.44.dist-info/METADATA,sha256=B4obUEzYdgylfnXg0jXVrDYWXbDuYer5ArhQin-HK3o,6640
7
+ hermes_client_python-1.8.44.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
8
+ hermes_client_python-1.8.44.dist-info/RECORD,,