chroma-haystack 4.3.2__tar.gz → 4.4.0__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 (59) hide show
  1. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/CHANGELOG.md +7 -0
  2. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/PKG-INFO +1 -1
  3. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/src/haystack_integrations/components/retrievers/chroma/retriever.py +12 -0
  4. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/src/haystack_integrations/document_stores/chroma/document_store.py +32 -24
  5. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/tests/test_document_store.py +85 -6
  6. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/tests/test_document_store_async.py +34 -0
  7. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/tests/test_retriever.py +18 -0
  8. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/.gitignore +0 -0
  9. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/LICENSE +0 -0
  10. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/README.md +0 -0
  11. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_01.txt +0 -0
  12. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_02.txt +0 -0
  13. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_03.txt +0 -0
  14. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_04.txt +0 -0
  15. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_05.txt +0 -0
  16. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_06.txt +0 -0
  17. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_07.txt +0 -0
  18. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_08.txt +0 -0
  19. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_09.txt +0 -0
  20. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_10.txt +0 -0
  21. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_11.txt +0 -0
  22. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_12.txt +0 -0
  23. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_20.txt +0 -0
  24. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_21.txt +0 -0
  25. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_22.txt +0 -0
  26. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_23.txt +0 -0
  27. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_24.txt +0 -0
  28. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_25.txt +0 -0
  29. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_26.txt +0 -0
  30. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_27.txt +0 -0
  31. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_28.txt +0 -0
  32. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_29.txt +0 -0
  33. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_30.txt +0 -0
  34. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_31.txt +0 -0
  35. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_32.txt +0 -0
  36. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_40.txt +0 -0
  37. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_41.txt +0 -0
  38. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_42.txt +0 -0
  39. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_43.txt +0 -0
  40. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_44.txt +0 -0
  41. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_45.txt +0 -0
  42. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_46.txt +0 -0
  43. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_50.txt +0 -0
  44. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_51.txt +0 -0
  45. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_52.txt +0 -0
  46. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/data/usr_90.txt +0 -0
  47. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/example/example.py +0 -0
  48. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/pydoc/config_docusaurus.yml +0 -0
  49. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/pyproject.toml +0 -0
  50. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/src/haystack_integrations/components/retrievers/chroma/__init__.py +0 -0
  51. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/src/haystack_integrations/components/retrievers/py.typed +0 -0
  52. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/src/haystack_integrations/document_stores/chroma/__init__.py +0 -0
  53. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/src/haystack_integrations/document_stores/chroma/errors.py +0 -0
  54. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/src/haystack_integrations/document_stores/chroma/filters.py +0 -0
  55. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/src/haystack_integrations/document_stores/chroma/utils.py +0 -0
  56. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/src/haystack_integrations/document_stores/py.typed +0 -0
  57. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/tests/__init__.py +0 -0
  58. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/tests/conftest.py +0 -0
  59. {chroma_haystack-4.3.2 → chroma_haystack-4.4.0}/tests/test_filters.py +0 -0
@@ -1,5 +1,12 @@
1
1
  # Changelog
2
2
 
3
+ ## [integrations/chroma-v4.3.2] - 2026-07-17
4
+
5
+ ### 🐛 Bug Fixes
6
+
7
+ - *(chroma)* Raise a clear error for id filters with a non-'==' operator (#3587)
8
+
9
+
3
10
  ## [integrations/chroma-v4.3.1] - 2026-06-29
4
11
 
5
12
  ### 🐛 Bug Fixes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: chroma-haystack
3
- Version: 4.3.2
3
+ Version: 4.4.0
4
4
  Project-URL: Documentation, https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/chroma#readme
5
5
  Project-URL: Issues, https://github.com/deepset-ai/haystack-core-integrations/issues
6
6
  Project-URL: Source, https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/chroma
@@ -119,6 +119,12 @@ class ChromaQueryTextRetriever:
119
119
  top_k = top_k or self.top_k
120
120
  return {"documents": (await self.document_store.search_async([query], top_k, filters))[0]}
121
121
 
122
+ def close(self) -> None:
123
+ """
124
+ Release the synchronous resources of the underlying Document Store.
125
+ """
126
+ self.document_store.close()
127
+
122
128
  @classmethod
123
129
  def from_dict(cls, data: dict[str, Any]) -> "ChromaQueryTextRetriever":
124
130
  """
@@ -238,6 +244,12 @@ class ChromaEmbeddingRetriever:
238
244
  query_embeddings = [query_embedding]
239
245
  return {"documents": (await self.document_store.search_embeddings_async(query_embeddings, top_k, filters))[0]}
240
246
 
247
+ def close(self) -> None:
248
+ """
249
+ Release the synchronous resources of the underlying Document Store.
250
+ """
251
+ self.document_store.close()
252
+
241
253
  @classmethod
242
254
  def from_dict(cls, data: dict[str, Any]) -> "ChromaEmbeddingRetriever":
243
255
  """
@@ -3,9 +3,11 @@
3
3
  # SPDX-License-Identifier: Apache-2.0
4
4
 
5
5
  from collections.abc import Sequence
6
+ from contextlib import suppress
6
7
  from typing import Any, Literal, cast
7
8
 
8
9
  import chromadb
10
+ from chromadb.api import ClientAPI
9
11
  from chromadb.api.models.AsyncCollection import AsyncCollection
10
12
  from chromadb.api.types import GetResult, Metadata, OneOrMany, QueryResult
11
13
  from chromadb.config import Settings
@@ -101,6 +103,7 @@ class ChromaDocumentStore:
101
103
  self._host = host
102
104
  self._port = port
103
105
 
106
+ self._client: ClientAPI | None = None
104
107
  self._collection: chromadb.Collection | None = None
105
108
  self._async_collection: AsyncCollection | None = None
106
109
 
@@ -138,7 +141,7 @@ class ChromaDocumentStore:
138
141
  # Local persistent storage
139
142
  client = chromadb.PersistentClient(path=self._persist_path, **client_kwargs)
140
143
 
141
- self._client = client # store client for potential future use
144
+ self._client = client
142
145
 
143
146
  # Build the collection metadata locally so `self._metadata` stays exactly as the user passed it.
144
147
  # This keeps `to_dict()` deterministic and avoids mutating a user-supplied dict in place.
@@ -213,6 +216,15 @@ class ChromaDocumentStore:
213
216
  embedding_function=self._embedding_func,
214
217
  )
215
218
 
219
+ def close(self) -> None:
220
+ """Release the associated synchronous resources."""
221
+ if self._client is not None:
222
+ with suppress(Exception):
223
+ # `close` is not declared on the `ClientAPI` interface, but the concrete Chroma clients implement it
224
+ self._client.close() # type: ignore[attr-defined]
225
+ self._client = None
226
+ self._collection = None
227
+
216
228
  @staticmethod
217
229
  def _prepare_get_kwargs(filters: dict[str, Any] | None = None) -> dict[str, Any]:
218
230
  """
@@ -356,7 +368,8 @@ class ChromaDocumentStore:
356
368
 
357
369
  :param result: The full GetResult from a Chroma collection get operation.
358
370
  :param field_name: The metadata field name to collect unique values for.
359
- :param search_term: Optional search term to filter documents by content.
371
+ :param search_term: Optional search term to filter by, matched as a case-insensitive
372
+ substring against the value of `field_name`.
360
373
  :param from_: The offset to start returning values from.
361
374
  :param size: The maximum number of unique values to return.
362
375
  :returns: A tuple of the paginated unique values list and the total count.
@@ -367,13 +380,15 @@ class ChromaDocumentStore:
367
380
  return [], 0
368
381
 
369
382
  if search_term:
370
- documents = result.get("documents")
371
- if documents is None:
372
- documents = []
373
- filtered_metadatas = [
374
- metadatas[i] for i in range(len(documents)) if documents[i] and search_term in documents[i]
383
+ search_term_lower = search_term.lower()
384
+ metadatas = [
385
+ meta
386
+ for meta in metadatas
387
+ if meta
388
+ and field_name in meta
389
+ and meta.get(field_name) is not None
390
+ and search_term_lower in str(meta.get(field_name)).lower()
375
391
  ]
376
- metadatas = filtered_metadatas
377
392
 
378
393
  if not metadatas:
379
394
  return [], 0
@@ -901,6 +916,7 @@ class ChromaDocumentStore:
901
916
  """
902
917
  self._ensure_initialized() # _ensure_initialized ensures _client is not None and a collection exists
903
918
  assert self._collection is not None
919
+ assert self._client is not None
904
920
 
905
921
  try:
906
922
  if recreate_index:
@@ -1294,12 +1310,12 @@ class ChromaDocumentStore:
1294
1310
  size: int = 10,
1295
1311
  ) -> tuple[list[str], int]:
1296
1312
  """
1297
- Return unique metadata field values, optionally filtered by a content search term, with pagination.
1313
+ Return unique metadata field values, optionally filtered by a search term, with pagination.
1298
1314
 
1299
1315
  :param metadata_field: The metadata field to get unique values for.
1300
1316
  Can include or omit the "meta." prefix.
1301
- :param search_term: Optional search term to filter documents by matching
1302
- in the content field.
1317
+ :param search_term: Optional search term to filter values, matched as a
1318
+ case-insensitive substring against the metadata field's value.
1303
1319
  :param from_: The offset to start returning values from (for pagination).
1304
1320
  :param size: The maximum number of unique values to return.
1305
1321
  :returns: A tuple containing list of unique values and total count of unique values.
@@ -1309,11 +1325,7 @@ class ChromaDocumentStore:
1309
1325
 
1310
1326
  field_name = _normalize_metadata_field_name(metadata_field)
1311
1327
 
1312
- kwargs: dict[str, Any] = {"include": ["metadatas"]}
1313
- if search_term:
1314
- kwargs["include"] = ["metadatas", "documents"]
1315
-
1316
- result = self._collection.get(**kwargs)
1328
+ result = self._collection.get(include=["metadatas"])
1317
1329
  return self._compute_field_unique_values(result, field_name, search_term, from_, size)
1318
1330
 
1319
1331
  async def get_metadata_field_unique_values_async(
@@ -1324,14 +1336,14 @@ class ChromaDocumentStore:
1324
1336
  size: int = 10,
1325
1337
  ) -> tuple[list[str], int]:
1326
1338
  """
1327
- Asynchronously return unique metadata field values, optionally filtered by content, with pagination.
1339
+ Asynchronously return unique metadata field values, optionally filtered by a search term, with pagination.
1328
1340
 
1329
1341
  Asynchronous methods are only supported for HTTP connections.
1330
1342
 
1331
1343
  :param metadata_field: The metadata field to get unique values for.
1332
1344
  Can include or omit the "meta." prefix.
1333
- :param search_term: Optional search term to filter documents by matching
1334
- in the content field.
1345
+ :param search_term: Optional search term to filter values, matched as a
1346
+ case-insensitive substring against the metadata field's value.
1335
1347
  :param from_: The offset to start returning values from (for pagination).
1336
1348
  :param size: The maximum number of unique values to return.
1337
1349
  :returns: A tuple containing list of unique values and total count of unique values.
@@ -1341,11 +1353,7 @@ class ChromaDocumentStore:
1341
1353
 
1342
1354
  field_name = _normalize_metadata_field_name(metadata_field)
1343
1355
 
1344
- kwargs: dict[str, Any] = {"include": ["metadatas"]}
1345
- if search_term:
1346
- kwargs["include"] = ["metadatas", "documents"]
1347
-
1348
- result = await self._async_collection.get(**kwargs)
1356
+ result = await self._async_collection.get(include=["metadatas"])
1349
1357
  return self._compute_field_unique_values(result, field_name, search_term, from_, size)
1350
1358
 
1351
1359
  @classmethod
@@ -180,6 +180,29 @@ class TestDocumentStoreUnit:
180
180
  with pytest.raises(ValueError, match="Invalid client_settings"):
181
181
  store._ensure_initialized()
182
182
 
183
+ def test_close(self):
184
+ store = ChromaDocumentStore()
185
+ client = mock.Mock()
186
+ store._client = client
187
+
188
+ store.close()
189
+
190
+ client.close.assert_called_once()
191
+ assert store._client is None
192
+
193
+ store.close()
194
+ client.close.assert_called_once()
195
+
196
+ def test_close_is_exception_safe(self):
197
+ store = ChromaDocumentStore()
198
+ client = mock.Mock()
199
+ client.close.side_effect = RuntimeError("boom")
200
+ store._client = client
201
+
202
+ store.close()
203
+
204
+ assert store._client is None
205
+
183
206
  def test_infer_type_from_value_fallback_for_unknown_type(self):
184
207
  assert ChromaDocumentStore._infer_type_from_value(None) == "keyword"
185
208
  assert ChromaDocumentStore._infer_type_from_value(["a", "b"]) == "keyword"
@@ -196,10 +219,11 @@ class TestDocumentStoreUnit:
196
219
  @pytest.mark.parametrize(
197
220
  "result",
198
221
  [
199
- {"ids": ["1"], "documents": None, "metadatas": [{"cat": "A"}]},
200
- {"ids": ["1"], "documents": ["hello world"], "metadatas": [{"cat": "A"}]},
222
+ {"ids": ["1"], "metadatas": [{"cat": "A"}]},
223
+ {"ids": ["1"], "metadatas": [None]},
224
+ {"ids": ["1"], "metadatas": [{"other": "A"}]},
201
225
  ],
202
- ids=["documents_none", "no_matches"],
226
+ ids=["no_match", "metadata_none", "field_missing"],
203
227
  )
204
228
  def test_compute_field_unique_values_with_search_term_edge_cases(self, result):
205
229
  values, total = ChromaDocumentStore._compute_field_unique_values(result, "cat", "absent", 0, 10)
@@ -377,6 +401,16 @@ class TestDocumentStore(
377
401
  assert store._collection.metadata["hnsw:space"] == "ip"
378
402
  assert new_store._collection.metadata["hnsw:space"] == "ip"
379
403
 
404
+ def test_close_and_reopen(self, tmp_path):
405
+ store = ChromaDocumentStore(collection_name="test_close_and_reopen", persist_path=str(tmp_path))
406
+ store.write_documents([Document(content="doc", embedding=TEST_EMBEDDING_1)])
407
+ assert store.count_documents() == 1
408
+
409
+ store.close()
410
+ assert store._client is None
411
+
412
+ assert store.count_documents() == 1
413
+
380
414
  def test_delete_empty(self, document_store: ChromaDocumentStore):
381
415
  """
382
416
  Deleting a non-existing document should not raise with Chroma
@@ -741,12 +775,57 @@ class TestMetadataOperations:
741
775
  assert sorted(all_values) == ["A", "B", "C"]
742
776
 
743
777
  def test_get_metadata_field_unique_values_with_search_term(self, populated_store):
744
- """Test getting unique values filtered by search term"""
745
- # Search for documents containing "Doc 1"
778
+ """Test getting unique values filtered by search term.
779
+
780
+ The search term is matched against the metadata field's own value, not document
781
+ content. "Doc 1" is content for one document (category "A"), but it is not a
782
+ substring of any "category" value, so no values should match.
783
+ """
746
784
  values, total = populated_store.get_metadata_field_unique_values(
747
785
  "category", search_term="Doc 1", from_=0, size=10
748
786
  )
749
- assert values == ["A"] # Only Doc 1 has category A
787
+ assert values == []
788
+ assert total == 0
789
+
790
+ def test_get_metadata_field_unique_values_search_term_matches_field_value(self, populated_store):
791
+ """Search term matches when it's a case-insensitive substring of the field's value."""
792
+ values, total = populated_store.get_metadata_field_unique_values("status", search_term="ACT", from_=0, size=10)
793
+ # "ACT" is a substring of both "active" and "inactive" (case-insensitive)
794
+ assert sorted(values) == ["active", "inactive"]
795
+ assert total == 2
796
+
797
+ values, total = populated_store.get_metadata_field_unique_values("status", search_term="ina", from_=0, size=10)
798
+ assert values == ["inactive"]
799
+ assert total == 1
800
+
801
+ def test_get_metadata_field_unique_values_search_term_excludes_content_only_match(self, document_store):
802
+ """A search term present only in document content (not in the metadata field value)
803
+ must not match, proving search_term no longer filters on content."""
804
+ docs = [
805
+ Document(content="unique-marker-xyz", meta={"category": "A"}),
806
+ Document(content="plain content", meta={"category": "B"}),
807
+ ]
808
+ document_store.write_documents(docs)
809
+
810
+ values, total = document_store.get_metadata_field_unique_values(
811
+ "category", search_term="unique-marker-xyz", from_=0, size=10
812
+ )
813
+ assert values == []
814
+ assert total == 0
815
+
816
+ def test_get_metadata_field_unique_values_search_term_matches_field_value_not_content(self, document_store):
817
+ """A search term present in the metadata field's value but absent from the content
818
+ must match, proving search_term filters on the metadata field's value."""
819
+ docs = [
820
+ Document(content="Nothing special here", meta={"category": "special-value"}),
821
+ Document(content="Nothing special here either", meta={"category": "other"}),
822
+ ]
823
+ document_store.write_documents(docs)
824
+
825
+ values, total = document_store.get_metadata_field_unique_values(
826
+ "category", search_term="SPECIAL", from_=0, size=10
827
+ )
828
+ assert values == ["special-value"]
750
829
  assert total == 1
751
830
 
752
831
  def test_get_metadata_field_unique_values_field_normalization(self, populated_store):
@@ -215,3 +215,37 @@ class TestDocumentStoreAsync(
215
215
  )
216
216
  assert values == []
217
217
  assert total == 0
218
+
219
+ async def test_get_metadata_field_unique_values_async_search_term_excludes_content_only_match(
220
+ self, document_store: ChromaDocumentStore
221
+ ):
222
+ """A search term present only in document content (not in the metadata field value)
223
+ must not match, proving search_term no longer filters on content."""
224
+ docs = [
225
+ Document(content="unique-marker-xyz", meta={"category": "A"}),
226
+ Document(content="plain content", meta={"category": "B"}),
227
+ ]
228
+ await document_store.write_documents_async(docs)
229
+
230
+ values, total = await document_store.get_metadata_field_unique_values_async(
231
+ "category", search_term="unique-marker-xyz", from_=0, size=10
232
+ )
233
+ assert values == []
234
+ assert total == 0
235
+
236
+ async def test_get_metadata_field_unique_values_async_search_term_matches_field_value(
237
+ self, document_store: ChromaDocumentStore
238
+ ):
239
+ """A search term present in the metadata field's value but absent from the content
240
+ must match, proving search_term filters on the metadata field's value (case-insensitively)."""
241
+ docs = [
242
+ Document(content="Nothing special here", meta={"category": "special-value"}),
243
+ Document(content="Nothing special here either", meta={"category": "other"}),
244
+ ]
245
+ await document_store.write_documents_async(docs)
246
+
247
+ values, total = await document_store.get_metadata_field_unique_values_async(
248
+ "category", search_term="SPECIAL", from_=0, size=10
249
+ )
250
+ assert values == ["special-value"]
251
+ assert total == 1
@@ -106,6 +106,15 @@ class TestChromaQueryTextRetriever:
106
106
  assert retriever.top_k == 42
107
107
  assert retriever.filter_policy == FilterPolicy.REPLACE # default even if not specified
108
108
 
109
+ def test_close(self):
110
+ ds = mock.Mock(spec=ChromaDocumentStore)
111
+ retriever = ChromaQueryTextRetriever(ds)
112
+
113
+ retriever.close()
114
+
115
+ ds.close.assert_called_once()
116
+ assert retriever.document_store is ds
117
+
109
118
  def test_run_delegates_to_document_store_search(self):
110
119
  ds = mock.Mock(spec=ChromaDocumentStore)
111
120
  expected = [Document(content="hit")]
@@ -215,6 +224,15 @@ class TestChromaEmbeddingRetriever:
215
224
  retriever = ChromaEmbeddingRetriever.from_dict(data)
216
225
  assert retriever.filter_policy == FilterPolicy.REPLACE
217
226
 
227
+ def test_close(self):
228
+ ds = mock.Mock(spec=ChromaDocumentStore)
229
+ retriever = ChromaEmbeddingRetriever(ds)
230
+
231
+ retriever.close()
232
+
233
+ ds.close.assert_called_once()
234
+ assert retriever.document_store is ds
235
+
218
236
  def test_run_delegates_to_document_store_search_embeddings(self):
219
237
  ds = mock.Mock(spec=ChromaDocumentStore)
220
238
  expected = [Document(content="hit")]
File without changes