howler-client 3.1.0.dev340__tar.gz → 3.1.0.dev345__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.
Files changed (30) hide show
  1. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/PKG-INFO +1 -1
  2. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/hit.py +44 -10
  3. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/user.py +26 -8
  4. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/v2/case.py +61 -17
  5. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/v2/ingest.py +18 -5
  6. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/pyproject.toml +1 -1
  7. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/LICENSE +0 -0
  8. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/README.md +0 -0
  9. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/__init__.py +0 -0
  10. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/client.py +0 -0
  11. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/common/__init__.py +0 -0
  12. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/common/dict_utils.py +0 -0
  13. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/common/utils.py +0 -0
  14. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/connection.py +0 -0
  15. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/logger.py +0 -0
  16. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/__init__.py +0 -0
  17. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/comment.py +0 -0
  18. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/help.py +0 -0
  19. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/search/__init__.py +0 -0
  20. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/search/chunk.py +0 -0
  21. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/search/facet.py +0 -0
  22. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/search/fields.py +0 -0
  23. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/search/grouped.py +0 -0
  24. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/search/histogram.py +0 -0
  25. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/search/stats.py +0 -0
  26. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/search/stream.py +0 -0
  27. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/v2/__init__.py +0 -0
  28. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/module/v2/search.py +0 -0
  29. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/utils/__init__.py +0 -0
  30. {howler_client-3.1.0.dev340 → howler_client-3.1.0.dev345}/howler_client/utils/json_encoders.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: howler-client
3
- Version: 3.1.0.dev340
3
+ Version: 3.1.0.dev345
4
4
  Summary: The Howler client library facilitates issuing requests to Howler
5
5
  License: MIT
6
6
  License-File: LICENSE
@@ -77,6 +77,7 @@ class Hit(object):
77
77
  map: dict[str, list[str]],
78
78
  documents: list[dict[str, Any]],
79
79
  ignore_extra_values: bool = False,
80
+ refresh: bool | Literal["true", "false", "wait_for"] = False,
80
81
  ) -> list[dict[str, str | list[str] | None]]:
81
82
  """Create hits for a given tool using the raw documents and a map of the document fields to howler's fields.
82
83
 
@@ -86,6 +87,8 @@ class Hit(object):
86
87
  the values are a list of flattened path for Howler's fields where the data will be copied into
87
88
  documents (list[dict[str, Any]]): The data to ingest into howler, in the tool's raw document format
88
89
  ignore_extra_values (bool, optional): Whether to allow extra fields, or raise an error. Defaults to False.
90
+ refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
91
+ Defaults to False.
89
92
 
90
93
  Returns:
91
94
  list[dict[str, str | list[str] | None]]: One entry per document, each with keys ``id``, ``error``,
@@ -103,7 +106,7 @@ class Hit(object):
103
106
 
104
107
  try:
105
108
  result = self._connection.post(
106
- api_path("tools", tool_name, "hits", ignore_extra_values=ignore_extra_values),
109
+ api_path("tools", tool_name, "hits", ignore_extra_values=ignore_extra_values, refresh=refresh),
107
110
  json=data,
108
111
  )
109
112
  except ClientError as e:
@@ -155,6 +158,7 @@ class Hit(object):
155
158
  self: Self,
156
159
  data: dict[str, Any] | list[dict[str, Any]],
157
160
  ignore_extra_values: bool = False,
161
+ refresh: bool | Literal["true", "false", "wait_for"] = False,
158
162
  ) -> CreateHitsResponse | None:
159
163
  """Create one or many hits using the howler schema.
160
164
 
@@ -162,6 +166,8 @@ class Hit(object):
162
166
  data (dict[str, Any] | list[dict[str, Any]]): The hit or list of hits to create
163
167
  ignore_extra_values (bool, optional): Whtether to ignore extra values, or throw an exception.
164
168
  Defaults to False.
169
+ refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
170
+ Defaults to False.
165
171
 
166
172
  Returns:
167
173
  CreateHitsResponse | None: Created and invalid hits with warnings, or ``None`` when no
@@ -217,7 +223,7 @@ class Hit(object):
217
223
  return None
218
224
 
219
225
  result = self._connection.post(
220
- api_path("hit", ignore_extra_values=ignore_extra_values),
226
+ api_path("hit", ignore_extra_values=ignore_extra_values, refresh=refresh),
221
227
  data=json.dumps(final_hit_list, cls=DatetimeEncoder),
222
228
  headers={"Content-Type": "application/json"},
223
229
  )
@@ -231,7 +237,12 @@ class Hit(object):
231
237
 
232
238
  return result
233
239
 
234
- def overwrite(self: Self, hit_id: str, new_hit_data: dict[str, Any]):
240
+ def overwrite(
241
+ self: Self,
242
+ hit_id: str,
243
+ new_hit_data: dict[str, Any],
244
+ refresh: bool | Literal["true", "false", "wait_for"] = False,
245
+ ):
235
246
  """Overwrite a hit.
236
247
 
237
248
  This is different from updating a hit, as you simply provide a partial hit object
@@ -246,9 +257,14 @@ class Hit(object):
246
257
  if not isinstance(new_hit_data, dict):
247
258
  raise TypeError("New hit data must be of type dict.")
248
259
 
249
- return self._connection.put(api_path(f"hit/{hit_id}/overwrite"), json=new_hit_data)
260
+ return self._connection.put(api_path(f"hit/{hit_id}/overwrite", refresh=refresh), json=new_hit_data)
250
261
 
251
- def update(self: Self, hit_id: str, updates: list[tuple[str, str, Any]]):
262
+ def update(
263
+ self: Self,
264
+ hit_id: str,
265
+ updates: list[tuple[str, str, Any]],
266
+ refresh: bool | Literal["true", "false", "wait_for"] = False,
267
+ ):
252
268
  """Update a hit.
253
269
 
254
270
  Args:
@@ -256,6 +272,8 @@ class Hit(object):
256
272
  updates (list[tuple[str, str, Any]]): A list of updates to run. The first entry in the tuple must be a valid
257
273
  update operation (see UPDATE_OPERATIONS), the second a key for a howler hit, and the third the value
258
274
  to use in the operation.
275
+ refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
276
+ Defaults to False.
259
277
 
260
278
  Raises:
261
279
  ClientError: Updates provided were invalid
@@ -273,9 +291,14 @@ class Hit(object):
273
291
  400,
274
292
  )
275
293
 
276
- return self._connection.put(api_path(f"hit/{hit_id}/update"), json=updates)
294
+ return self._connection.put(api_path(f"hit/{hit_id}/update", refresh=refresh), json=updates)
277
295
 
278
- def update_by_query(self: Self, query: str, updates: list[tuple[str, str, Any]]):
296
+ def update_by_query(
297
+ self: Self,
298
+ query: str,
299
+ updates: list[tuple[str, str, Any]],
300
+ refresh: bool | Literal["true", "false", "wait_for"] = False,
301
+ ):
279
302
  """Update a set of hits by query.
280
303
 
281
304
  Args:
@@ -283,6 +306,8 @@ class Hit(object):
283
306
  updates (list[tuple[str, str, Any]]): A list of updates to run. The first entry in the tuple must be a valid
284
307
  update operation (see UPDATE_OPERATIONS), the second a key for a howler hit, and the third the value
285
308
  to use in the operation.
309
+ refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
310
+ Defaults to False.
286
311
 
287
312
  Raises:
288
313
  ClientError: Updates provided were invalid
@@ -299,15 +324,24 @@ class Hit(object):
299
324
  400,
300
325
  )
301
326
 
302
- return self._connection.put(api_path("hit/update"), json={"query": query, "operations": updates})
327
+ return self._connection.put(
328
+ api_path("hit/update", refresh=refresh), json={"query": query, "operations": updates}
329
+ )
303
330
 
304
- def delete(self: Self, hit_ids: list[str]) -> dict[Literal["success"], bool]:
331
+ def delete(
332
+ self: Self, hit_ids: list[str], refresh: bool | Literal["true", "false", "wait_for"] = False
333
+ ) -> dict[Literal["success"], bool]:
305
334
  """Delete a list of hits by id
306
335
 
336
+ Args:
337
+ hit_ids (list[str]): List of hit ids to delete
338
+ refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
339
+ Defaults to False.
340
+
307
341
  Returns:
308
342
  dict[Literal["success"], bool]: Whether the delete operation was successful
309
343
  """
310
344
  if not isinstance(hit_ids, list):
311
345
  hit_ids = [hit_ids]
312
346
 
313
- return self._connection.delete(api_path("hit"), json=hit_ids)
347
+ return self._connection.delete(api_path("hit", refresh=refresh), json=hit_ids)
@@ -26,28 +26,39 @@ class User(object):
26
26
  """
27
27
  return self._connection.get(api_path("user", username))
28
28
 
29
- def add(self: Self, username: str, user_data: dict[str, Any]) -> dict[Literal["success"], bool]:
29
+ def add(
30
+ self: Self,
31
+ username: str,
32
+ user_data: dict[str, Any],
33
+ refresh: bool | Literal["true", "false", "wait_for"] = False,
34
+ ) -> dict[Literal["success"], bool]:
30
35
  """Add a user to the system
31
36
 
32
37
  Args:
33
38
  username (str): Name of the user to add to the system
34
39
  user_data (dict[str, Any]): Profile data of the user to add
40
+ refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
41
+ Defaults to False.
35
42
 
36
43
  Returns:
37
44
  dict[Literal["success"], bool]: Whether creating the user succeeded
38
45
  """
39
- return self._connection.post(api_path("user", username), json=user_data)
46
+ return self._connection.post(api_path("user", username, refresh=refresh), json=user_data)
40
47
 
41
- def delete(self: Self, username: str) -> dict[Literal["success"], bool]:
48
+ def delete(
49
+ self: Self, username: str, refresh: bool | Literal["true", "false", "wait_for"] = False
50
+ ) -> dict[Literal["success"], bool]:
42
51
  """Remove the account specified by the username.
43
52
 
44
53
  Args:
45
- str: Name of the user to remove from the system
54
+ username (str): Name of the user to remove from the system
55
+ refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
56
+ Defaults to False.
46
57
 
47
58
  Returns:
48
59
  dict[Literal["success"], bool]: Whether the delete succeeded
49
60
  """
50
- return self._connection.delete(api_path("user", username))
61
+ return self._connection.delete(api_path("user", username, refresh=refresh))
51
62
 
52
63
  def list(
53
64
  self: Self,
@@ -60,7 +71,7 @@ class User(object):
60
71
  """List users of the system
61
72
 
62
73
  Args:
63
- query (_type_, optional): Filter to apply to the user list. Defaults to "*:*".
74
+ query (str, optional): Filter to apply to the user list. Defaults to "*:*".
64
75
  rows (int, optional): Total number of users returned. Defaults to 10.
65
76
  offset (int, optional): Offset in the user index. Defaults to 0.
66
77
  sort (str, optional): Sort order. Defaults to "uname asc".
@@ -80,17 +91,24 @@ class User(object):
80
91
  )
81
92
  )
82
93
 
83
- def update(self: Self, username: str, user_data: dict[str, Any]) -> dict[Literal["success"], bool]:
94
+ def update(
95
+ self: Self,
96
+ username: str,
97
+ user_data: dict[str, Any],
98
+ refresh: bool | Literal["true", "false", "wait_for"] = False,
99
+ ) -> dict[Literal["success"], bool]:
84
100
  """Update a user profile in the system.
85
101
 
86
102
  Args:
87
103
  username (str): Name of the user to update in the system
88
104
  user_data (dict[str, Any]): Profile data of the user to update
105
+ refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
106
+ Defaults to False.
89
107
 
90
108
  Returns:
91
109
  dict[Literal["success"], bool]: Whether the update succeeded
92
110
  """
93
- return self._connection.put(api_path("user", username), json=user_data)
111
+ return self._connection.put(api_path("user", username, refresh=refresh), json=user_data)
94
112
 
95
113
  def whoami(self: Self) -> dict[str, Any]:
96
114
  "Return the currently logged in user"
@@ -42,36 +42,46 @@ class Case(object):
42
42
  """
43
43
  return self._connection.post(api_path_v2("case/"), json=case_data)
44
44
 
45
- def update(self: Self, case_id: str, updates: dict[str, Any]) -> dict[str, Any]:
45
+ def update(
46
+ self: Self, case_id: str, updates: dict[str, Any], refresh: bool | Literal["true", "false", "wait_for"] = False
47
+ ) -> dict[str, Any]:
46
48
  """Update fields on an existing case.
47
49
 
48
50
  Args:
49
51
  case_id: ID of the case to update.
50
52
  updates: Dictionary of fields to update.
53
+ refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
54
+ Defaults to False.
51
55
 
52
56
  Returns:
53
57
  The updated case data.
54
58
  """
55
- return self._connection.put(api_path_v2("case", case_id), json=updates)
59
+ return self._connection.put(api_path_v2("case", case_id, refresh=refresh), json=updates)
56
60
 
57
- def delete(self: Self, case_ids: list[str]) -> None:
61
+ def delete(self: Self, case_ids: list[str], refresh: bool | Literal["true", "false", "wait_for"] = False) -> None:
58
62
  """Delete one or more cases.
59
63
 
60
64
  Args:
61
65
  case_ids: List of case IDs to delete.
66
+ refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
67
+ Defaults to False.
62
68
  """
63
- return self._connection.delete(api_path_v2("case/"), json=case_ids)
69
+ return self._connection.delete(api_path_v2("case/", refresh=refresh), json=case_ids)
64
70
 
65
- def hide(self: Self, case_ids: list[str]) -> dict[Literal["success"], bool]:
71
+ def hide(
72
+ self: Self, case_ids: list[str], refresh: bool | Literal["true", "false", "wait_for"] = False
73
+ ) -> dict[Literal["success"], bool]:
66
74
  """Hide one or more cases.
67
75
 
68
76
  Args:
69
77
  case_ids: List of case IDs to hide.
78
+ refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
79
+ Defaults to False.
70
80
 
71
81
  Returns:
72
82
  Whether the operation succeeded.
73
83
  """
74
- return self._connection.post(api_path_v2("case/hide"), json=case_ids)
84
+ return self._connection.post(api_path_v2("case/hide", refresh=refresh), json=case_ids)
75
85
 
76
86
  def append_item(
77
87
  self: Self,
@@ -81,6 +91,7 @@ class Case(object):
81
91
  path: str | None = None,
82
92
  name: str | None = None,
83
93
  parent: str | None = None,
94
+ refresh: bool | Literal["true", "false", "wait_for"] = False,
84
95
  ) -> dict[str, Any]:
85
96
  """Append an item to a case.
86
97
 
@@ -92,6 +103,8 @@ class Case(object):
92
103
  name: Optional display name for the item. Defaults to ``value``.
93
104
  parent: Optional parent folder item ID. If both ``path`` and ``parent``
94
105
  are provided, the API resolves and applies ``path``.
106
+ refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
107
+ Defaults to False.
95
108
 
96
109
  Returns:
97
110
  The updated case data.
@@ -107,71 +120,102 @@ class Case(object):
107
120
  payload["path"] = path
108
121
 
109
122
  return self._connection.post(
110
- api_path_v2("case", case_id, "items"),
123
+ api_path_v2("case", case_id, "items", refresh=refresh),
111
124
  json=payload,
112
125
  )
113
126
 
114
- def delete_items(self: Self, case_id: str, item_ids: list[str]) -> dict[str, Any]:
127
+ def delete_items(
128
+ self: Self, case_id: str, item_ids: list[str], refresh: bool | Literal["true", "false", "wait_for"] = False
129
+ ) -> dict[str, Any]:
115
130
  """Remove items from a case.
116
131
 
117
132
  Args:
118
133
  case_id: ID of the case.
119
134
  item_ids: List of item IDs to remove.
135
+ refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
136
+ Defaults to False.
120
137
 
121
138
  Returns:
122
139
  The updated case data.
123
140
  """
124
- return self._connection.delete(api_path_v2("case", case_id, "items"), json={"ids": item_ids})
141
+ return self._connection.delete(api_path_v2("case", case_id, "items", refresh=refresh), json={"ids": item_ids})
125
142
 
126
- def rename_item(self: Self, case_id: str, item_id: str, new_name: str) -> dict[str, Any]:
143
+ def rename_item(
144
+ self: Self,
145
+ case_id: str,
146
+ item_id: str,
147
+ new_name: str,
148
+ refresh: bool | Literal["true", "false", "wait_for"] = False,
149
+ ) -> dict[str, Any]:
127
150
  """Rename an item within a case.
128
151
 
129
152
  Args:
130
153
  case_id: ID of the case.
131
154
  item_id: ID identifying the item to rename.
132
155
  new_name: New display name for the item.
156
+ refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
157
+ Defaults to False.
133
158
 
134
159
  Returns:
135
160
  The updated case data.
136
161
  """
137
162
  return self._connection.put(
138
- api_path_v2("case", case_id, "items"),
163
+ api_path_v2("case", case_id, "items", refresh=refresh),
139
164
  json={"id": item_id, "name": new_name},
140
165
  )
141
166
 
142
- def add_rule(self: Self, case_id: str, rule_data: dict[str, Any]) -> dict[str, Any]:
167
+ def add_rule(
168
+ self: Self,
169
+ case_id: str,
170
+ rule_data: dict[str, Any],
171
+ refresh: bool | Literal["true", "false", "wait_for"] = False,
172
+ ) -> dict[str, Any]:
143
173
  """Add a correlation rule to a case.
144
174
 
145
175
  Args:
146
176
  case_id: ID of the case.
147
177
  rule_data: Rule definition (must include ``query``, ``destination``, ``author``).
178
+ refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
179
+ Defaults to False.
148
180
 
149
181
  Returns:
150
182
  The updated case data.
151
183
  """
152
- return self._connection.post(api_path_v2("case", case_id, "rules"), json=rule_data)
184
+ return self._connection.post(api_path_v2("case", case_id, "rules", refresh=refresh), json=rule_data)
153
185
 
154
- def delete_rule(self: Self, case_id: str, rule_id: str) -> dict[str, Any]:
186
+ def delete_rule(
187
+ self: Self, case_id: str, rule_id: str, refresh: bool | Literal["true", "false", "wait_for"] = False
188
+ ) -> dict[str, Any]:
155
189
  """Delete a correlation rule from a case.
156
190
 
157
191
  Args:
158
192
  case_id: ID of the case.
159
193
  rule_id: ID of the rule to delete.
194
+ refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
195
+ Defaults to False.
160
196
 
161
197
  Returns:
162
198
  The updated case data.
163
199
  """
164
- return self._connection.delete(api_path_v2("case", case_id, "rules", rule_id))
200
+ return self._connection.delete(api_path_v2("case", case_id, "rules", rule_id, refresh=refresh))
165
201
 
166
- def update_rule(self: Self, case_id: str, rule_id: str, rule_data: dict[str, Any]) -> dict[str, Any]:
202
+ def update_rule(
203
+ self: Self,
204
+ case_id: str,
205
+ rule_id: str,
206
+ rule_data: dict[str, Any],
207
+ refresh: bool | Literal["true", "false", "wait_for"] = False,
208
+ ) -> dict[str, Any]:
167
209
  """Update a correlation rule on a case.
168
210
 
169
211
  Args:
170
212
  case_id: ID of the case.
171
213
  rule_id: ID of the rule to update.
172
214
  rule_data: Updated rule fields.
215
+ refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
216
+ Defaults to False.
173
217
 
174
218
  Returns:
175
219
  The updated case data.
176
220
  """
177
- return self._connection.put(api_path_v2("case", case_id, "rules", rule_id), json=rule_data)
221
+ return self._connection.put(api_path_v2("case", case_id, "rules", rule_id, refresh=refresh), json=rule_data)
@@ -42,12 +42,15 @@ class Ingest(object):
42
42
  self: Self,
43
43
  index: str,
44
44
  data: Union[dict[str, Any], list[dict[str, Any]]],
45
+ refresh: bool | Literal["true", "false", "wait_for"] = False,
45
46
  ) -> list[str]:
46
47
  """Create one or more records in the given index.
47
48
 
48
49
  Args:
49
50
  index: Target index (``hit`` or ``event``).
50
51
  data: A single record dict or a list of record dicts.
52
+ refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
53
+ Defaults to False.
51
54
 
52
55
  Returns:
53
56
  List of created record IDs.
@@ -56,22 +59,26 @@ class Ingest(object):
56
59
  data = [data]
57
60
 
58
61
  return self._connection.post(
59
- api_path_v2("ingest", index),
62
+ api_path_v2("ingest", index, refresh=refresh),
60
63
  data=json.dumps(data),
61
64
  headers={"Content-Type": "application/json"},
62
65
  )
63
66
 
64
- def delete(self: Self, indexes: str, ids: list[str]) -> dict[str, Any]:
67
+ def delete(
68
+ self: Self, indexes: str, ids: list[str], refresh: bool | Literal["true", "false", "wait_for"] = False
69
+ ) -> dict[str, Any]:
65
70
  """Delete records across one or more indexes.
66
71
 
67
72
  Args:
68
73
  indexes: Comma-separated index names (e.g. ``"hit"`` or ``"hit,event"``).
69
74
  ids: List of record IDs to delete.
75
+ refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
76
+ Defaults to False.
70
77
 
71
78
  Returns:
72
79
  Dictionary with deletion results.
73
80
  """
74
- return self._connection.delete(api_path_v2("ingest", indexes), json=ids)
81
+ return self._connection.delete(api_path_v2("ingest", indexes, refresh=refresh), json=ids)
75
82
 
76
83
  def validate(
77
84
  self: Self,
@@ -102,6 +109,7 @@ class Ingest(object):
102
109
  record_id: str,
103
110
  new_data: dict[str, Any],
104
111
  replace: bool = False,
112
+ refresh: bool | Literal["true", "false", "wait_for"] = False,
105
113
  ) -> dict[str, Any]:
106
114
  """Overwrite (patch) a single record.
107
115
 
@@ -110,6 +118,8 @@ class Ingest(object):
110
118
  record_id: ID of the record to overwrite.
111
119
  new_data: Partial record data to merge.
112
120
  replace: If ``True``, lists are replaced instead of merged.
121
+ refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
122
+ Defaults to False.
113
123
 
114
124
  Returns:
115
125
  The updated record data.
@@ -119,7 +129,7 @@ class Ingest(object):
119
129
 
120
130
  return self._connection.request(
121
131
  self._connection.session.patch,
122
- api_path_v2("ingest", index, record_id, "overwrite", replace=replace if replace else None),
132
+ api_path_v2("ingest", index, record_id, "overwrite", replace=replace if replace else None, refresh=refresh),
123
133
  lambda resp: resp.json()["api_response"],
124
134
  json=new_data,
125
135
  )
@@ -129,6 +139,7 @@ class Ingest(object):
129
139
  indexes: str,
130
140
  query: str,
131
141
  operations: list[tuple[str, str, Any]],
142
+ refresh: bool | Literal["true", "false", "wait_for"] = False,
132
143
  ) -> dict[Literal["success"], bool]:
133
144
  """Bulk update records matching a query.
134
145
 
@@ -138,6 +149,8 @@ class Ingest(object):
138
149
  operations: List of ``(operation, key, value)`` tuples.
139
150
  Valid operations: SET, INC, DEC, MAX, MIN, APPEND,
140
151
  APPEND_IF_MISSING, REMOVE, DELETE.
152
+ refresh (bool | Literal["true", "false", "wait_for"], optional): Whether to refresh the index.
153
+ Defaults to False.
141
154
 
142
155
  Returns:
143
156
  Whether the operation succeeded.
@@ -155,6 +168,6 @@ class Ingest(object):
155
168
  )
156
169
 
157
170
  return self._connection.put(
158
- api_path_v2("ingest", indexes, "update"),
171
+ api_path_v2("ingest", indexes, "update", refresh=refresh),
159
172
  json={"query": query, "operations": operations},
160
173
  )
@@ -91,7 +91,7 @@ suppress-none-returning = true
91
91
  [tool.poetry]
92
92
  package-mode = true
93
93
  name = "howler-client"
94
- version = "3.1.0.dev340"
94
+ version = "3.1.0.dev345"
95
95
  description = "The Howler client library facilitates issuing requests to Howler"
96
96
  authors = [
97
97
  "Canadian Centre for Cyber Security <howler@cyber.gc.ca>",