weaviate-haystack 2.0.0__tar.gz → 2.1.1__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.
- weaviate_haystack-2.1.1/CHANGELOG.md +51 -0
- {weaviate_haystack-2.0.0 → weaviate_haystack-2.1.1}/PKG-INFO +2 -1
- {weaviate_haystack-2.0.0 → weaviate_haystack-2.1.1}/pydoc/config.yml +1 -1
- {weaviate_haystack-2.0.0 → weaviate_haystack-2.1.1}/pyproject.toml +6 -9
- {weaviate_haystack-2.0.0 → weaviate_haystack-2.1.1}/src/haystack_integrations/document_stores/weaviate/document_store.py +88 -48
- {weaviate_haystack-2.0.0 → weaviate_haystack-2.1.1}/tests/test_document_store.py +60 -6
- {weaviate_haystack-2.0.0 → weaviate_haystack-2.1.1}/.gitignore +0 -0
- {weaviate_haystack-2.0.0 → weaviate_haystack-2.1.1}/LICENSE.txt +0 -0
- {weaviate_haystack-2.0.0 → weaviate_haystack-2.1.1}/README.md +0 -0
- {weaviate_haystack-2.0.0 → weaviate_haystack-2.1.1}/docker-compose.yml +0 -0
- {weaviate_haystack-2.0.0 → weaviate_haystack-2.1.1}/src/haystack_integrations/components/retrievers/weaviate/__init__.py +0 -0
- {weaviate_haystack-2.0.0 → weaviate_haystack-2.1.1}/src/haystack_integrations/components/retrievers/weaviate/bm25_retriever.py +0 -0
- {weaviate_haystack-2.0.0 → weaviate_haystack-2.1.1}/src/haystack_integrations/components/retrievers/weaviate/embedding_retriever.py +0 -0
- {weaviate_haystack-2.0.0 → weaviate_haystack-2.1.1}/src/haystack_integrations/document_stores/weaviate/__init__.py +0 -0
- {weaviate_haystack-2.0.0 → weaviate_haystack-2.1.1}/src/haystack_integrations/document_stores/weaviate/_filters.py +0 -0
- {weaviate_haystack-2.0.0 → weaviate_haystack-2.1.1}/src/haystack_integrations/document_stores/weaviate/auth.py +0 -0
- {weaviate_haystack-2.0.0 → weaviate_haystack-2.1.1}/tests/__init__.py +0 -0
- {weaviate_haystack-2.0.0 → weaviate_haystack-2.1.1}/tests/conftest.py +0 -0
- {weaviate_haystack-2.0.0 → weaviate_haystack-2.1.1}/tests/test_auth.py +0 -0
- {weaviate_haystack-2.0.0 → weaviate_haystack-2.1.1}/tests/test_bm25_retriever.py +0 -0
- {weaviate_haystack-2.0.0 → weaviate_haystack-2.1.1}/tests/test_embedding_retriever.py +0 -0
- {weaviate_haystack-2.0.0 → weaviate_haystack-2.1.1}/tests/test_files/robot1.jpg +0 -0
- {weaviate_haystack-2.0.0 → weaviate_haystack-2.1.1}/tests/test_filters.py +0 -0
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## [integrations/weaviate-v2.1.0] - 2024-06-10
|
|
4
|
+
|
|
5
|
+
### 🚀 Features
|
|
6
|
+
|
|
7
|
+
- Defer the database connection to when it's needed (#802)
|
|
8
|
+
|
|
9
|
+
### 🐛 Bug Fixes
|
|
10
|
+
|
|
11
|
+
- Weaviate schema class name conversion which preserves PascalCase (#707)
|
|
12
|
+
|
|
13
|
+
## [integrations/weaviate-v2.0.0] - 2024-03-25
|
|
14
|
+
|
|
15
|
+
### 📚 Documentation
|
|
16
|
+
|
|
17
|
+
- Disable-class-def (#556)
|
|
18
|
+
- Fix docstrings (#586)
|
|
19
|
+
|
|
20
|
+
### Weaviate
|
|
21
|
+
|
|
22
|
+
- Migrate from weaviate python client v3 to v4 (#463)
|
|
23
|
+
|
|
24
|
+
## [integrations/weaviate-v1.0.2] - 2024-02-27
|
|
25
|
+
|
|
26
|
+
### 🐛 Bug Fixes
|
|
27
|
+
|
|
28
|
+
- Fix order of API docs (#447)
|
|
29
|
+
|
|
30
|
+
This PR will also push the docs to Readme
|
|
31
|
+
- Fix weaviate auth tests (#488)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
### 📚 Documentation
|
|
36
|
+
|
|
37
|
+
- Update category slug (#442)
|
|
38
|
+
|
|
39
|
+
### Weaviate
|
|
40
|
+
|
|
41
|
+
- Make retrievers return dicts (#491)
|
|
42
|
+
|
|
43
|
+
## [integrations/weaviate-v1.0.0] - 2024-02-15
|
|
44
|
+
|
|
45
|
+
### 🚀 Features
|
|
46
|
+
|
|
47
|
+
- Generate weaviate API docs (#351)
|
|
48
|
+
|
|
49
|
+
## [integrations/weaviate-v0.0.0] - 2024-01-10
|
|
50
|
+
|
|
51
|
+
<!-- generated by git-cliff -->
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: weaviate-haystack
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.1.1
|
|
4
4
|
Summary: An integration of Weaviate vector database with Haystack
|
|
5
5
|
Project-URL: Source, https://github.com/deepset-ai/haystack-core-integrations
|
|
6
6
|
Project-URL: Documentation, https://github.com/deepset-ai/haystack-core-integrations/blob/main/integrations/weaviate/README.md
|
|
@@ -9,6 +9,7 @@ Author-email: deepset GmbH <info@deepset.ai>
|
|
|
9
9
|
License-Expression: Apache-2.0
|
|
10
10
|
License-File: LICENSE.txt
|
|
11
11
|
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
12
13
|
Classifier: Programming Language :: Python
|
|
13
14
|
Classifier: Programming Language :: Python :: 3.8
|
|
14
15
|
Classifier: Programming Language :: Python :: 3.9
|
|
@@ -18,7 +18,7 @@ processors:
|
|
|
18
18
|
- type: smart
|
|
19
19
|
- type: crossref
|
|
20
20
|
renderer:
|
|
21
|
-
type: haystack_pydoc_tools.renderers.
|
|
21
|
+
type: haystack_pydoc_tools.renderers.ReadmeIntegrationRenderer
|
|
22
22
|
excerpt: Weaviate integration for Haystack
|
|
23
23
|
category_slug: integrations-api
|
|
24
24
|
title: Weaviate
|
|
@@ -12,6 +12,7 @@ license = "Apache-2.0"
|
|
|
12
12
|
keywords = []
|
|
13
13
|
authors = [{ name = "deepset GmbH", email = "info@deepset.ai" }]
|
|
14
14
|
classifiers = [
|
|
15
|
+
"License :: OSI Approved :: Apache Software License",
|
|
15
16
|
"Development Status :: 4 - Beta",
|
|
16
17
|
"Programming Language :: Python",
|
|
17
18
|
"Programming Language :: Python :: 3.8",
|
|
@@ -46,10 +47,10 @@ root = "../.."
|
|
|
46
47
|
git_describe_command = 'git describe --tags --match="integrations/weaviate-v[0-9]*"'
|
|
47
48
|
|
|
48
49
|
[tool.hatch.envs.default]
|
|
49
|
-
dependencies = ["coverage[toml]>=6.5", "pytest", "ipython"]
|
|
50
|
+
dependencies = ["coverage[toml]>=6.5", "pytest", "pytest-rerunfailures", "ipython"]
|
|
50
51
|
[tool.hatch.envs.default.scripts]
|
|
51
|
-
test = "pytest {args:tests}"
|
|
52
|
-
test-cov = "coverage run -m pytest {args:tests}"
|
|
52
|
+
test = "pytest --reruns 3 --reruns-delay 30 -x {args:tests}"
|
|
53
|
+
test-cov = "coverage run -m pytest --reruns 3 --reruns-delay 30 -x {args:tests}"
|
|
53
54
|
cov-report = ["- coverage combine", "coverage report"]
|
|
54
55
|
cov = ["test-cov", "cov-report"]
|
|
55
56
|
docs = ["pydoc-markdown pydoc/config.yml"]
|
|
@@ -140,12 +141,8 @@ parallel = false
|
|
|
140
141
|
|
|
141
142
|
[tool.coverage.report]
|
|
142
143
|
omit = ["*/tests/*", "*/__init__.py"]
|
|
143
|
-
show_missing=true
|
|
144
|
-
exclude_lines = [
|
|
145
|
-
"no cov",
|
|
146
|
-
"if __name__ == .__main__.:",
|
|
147
|
-
"if TYPE_CHECKING:",
|
|
148
|
-
]
|
|
144
|
+
show_missing = true
|
|
145
|
+
exclude_lines = ["no cov", "if __name__ == .__main__.:", "if TYPE_CHECKING:"]
|
|
149
146
|
|
|
150
147
|
|
|
151
148
|
[[tool.mypy.overrides]]
|
|
@@ -12,6 +12,7 @@ from haystack.core.serialization import default_from_dict, default_to_dict
|
|
|
12
12
|
from haystack.dataclasses.document import Document
|
|
13
13
|
from haystack.document_stores.errors import DocumentStoreError, DuplicateDocumentError
|
|
14
14
|
from haystack.document_stores.types.policy import DuplicatePolicy
|
|
15
|
+
from haystack.utils.filters import convert
|
|
15
16
|
|
|
16
17
|
import weaviate
|
|
17
18
|
from weaviate.collections.classes.data import DataObject
|
|
@@ -139,47 +140,83 @@ class WeaviateDocumentStore:
|
|
|
139
140
|
:param grpc_secure:
|
|
140
141
|
Whether to use a secure channel for the underlying gRPC API.
|
|
141
142
|
"""
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
self.
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
143
|
+
self._url = url
|
|
144
|
+
self._auth_client_secret = auth_client_secret
|
|
145
|
+
self._additional_headers = additional_headers
|
|
146
|
+
self._embedded_options = embedded_options
|
|
147
|
+
self._additional_config = additional_config
|
|
148
|
+
self._grpc_port = grpc_port
|
|
149
|
+
self._grpc_secure = grpc_secure
|
|
150
|
+
self._client = None
|
|
151
|
+
self._collection = None
|
|
152
|
+
# Store the connection settings dictionary
|
|
153
|
+
self._collection_settings = collection_settings or {
|
|
154
|
+
"class": "Default",
|
|
155
|
+
"invertedIndexConfig": {"indexNullState": True},
|
|
156
|
+
"properties": DOCUMENT_COLLECTION_PROPERTIES,
|
|
157
|
+
}
|
|
158
|
+
self._clean_connection_settings()
|
|
159
|
+
|
|
160
|
+
def _clean_connection_settings(self):
|
|
161
|
+
# Set the class if not set
|
|
162
|
+
_class_name = self._collection_settings.get("class", "Default")
|
|
163
|
+
_class_name = _class_name[0].upper() + _class_name[1:]
|
|
164
|
+
self._collection_settings["class"] = _class_name
|
|
165
|
+
# Set the properties if they're not set
|
|
166
|
+
self._collection_settings["properties"] = self._collection_settings.get(
|
|
167
|
+
"properties", DOCUMENT_COLLECTION_PROPERTIES
|
|
155
168
|
)
|
|
169
|
+
|
|
170
|
+
@property
|
|
171
|
+
def client(self):
|
|
172
|
+
if self._client:
|
|
173
|
+
return self._client
|
|
174
|
+
|
|
175
|
+
if self._url and self._url.startswith("http") and self._url.endswith(".weaviate.network"):
|
|
176
|
+
# We use this utility function instead of using WeaviateClient directly like in other cases
|
|
177
|
+
# otherwise we'd have to parse the URL to get some information about the connection.
|
|
178
|
+
# This utility function does all that for us.
|
|
179
|
+
self._client = weaviate.connect_to_wcs(
|
|
180
|
+
self._url,
|
|
181
|
+
auth_credentials=self._auth_client_secret.resolve_value() if self._auth_client_secret else None,
|
|
182
|
+
headers=self._additional_headers,
|
|
183
|
+
additional_config=self._additional_config,
|
|
184
|
+
)
|
|
185
|
+
else:
|
|
186
|
+
# proxies, timeout_config, trust_env are part of additional_config now
|
|
187
|
+
# startup_period has been removed
|
|
188
|
+
self._client = weaviate.WeaviateClient(
|
|
189
|
+
connection_params=(
|
|
190
|
+
weaviate.connect.base.ConnectionParams.from_url(
|
|
191
|
+
url=self._url, grpc_port=self._grpc_port, grpc_secure=self._grpc_secure
|
|
192
|
+
)
|
|
193
|
+
if self._url
|
|
194
|
+
else None
|
|
195
|
+
),
|
|
196
|
+
auth_client_secret=self._auth_client_secret.resolve_value() if self._auth_client_secret else None,
|
|
197
|
+
additional_config=self._additional_config,
|
|
198
|
+
additional_headers=self._additional_headers,
|
|
199
|
+
embedded_options=self._embedded_options,
|
|
200
|
+
skip_init_checks=False,
|
|
201
|
+
)
|
|
202
|
+
|
|
156
203
|
self._client.connect()
|
|
157
204
|
|
|
158
205
|
# Test connection, it will raise an exception if it fails.
|
|
159
206
|
self._client.collections._get_all(simple=True)
|
|
207
|
+
if not self._client.collections.exists(self._collection_settings["class"]):
|
|
208
|
+
self._client.collections.create_from_dict(self._collection_settings)
|
|
160
209
|
|
|
161
|
-
|
|
162
|
-
collection_settings = {
|
|
163
|
-
"class": "Default",
|
|
164
|
-
"invertedIndexConfig": {"indexNullState": True},
|
|
165
|
-
"properties": DOCUMENT_COLLECTION_PROPERTIES,
|
|
166
|
-
}
|
|
167
|
-
else:
|
|
168
|
-
# Set the class if not set
|
|
169
|
-
collection_settings["class"] = collection_settings.get("class", "default").capitalize()
|
|
170
|
-
# Set the properties if they're not set
|
|
171
|
-
collection_settings["properties"] = collection_settings.get("properties", DOCUMENT_COLLECTION_PROPERTIES)
|
|
210
|
+
return self._client
|
|
172
211
|
|
|
173
|
-
|
|
174
|
-
|
|
212
|
+
@property
|
|
213
|
+
def collection(self):
|
|
214
|
+
if self._collection:
|
|
215
|
+
return self._collection
|
|
175
216
|
|
|
176
|
-
|
|
177
|
-
self.
|
|
178
|
-
self.
|
|
179
|
-
self._additional_headers = additional_headers
|
|
180
|
-
self._embedded_options = embedded_options
|
|
181
|
-
self._additional_config = additional_config
|
|
182
|
-
self._collection = self._client.collections.get(collection_settings["class"])
|
|
217
|
+
client = self.client
|
|
218
|
+
self._collection = client.collections.get(self._collection_settings["class"])
|
|
219
|
+
return self._collection
|
|
183
220
|
|
|
184
221
|
def to_dict(self) -> Dict[str, Any]:
|
|
185
222
|
"""
|
|
@@ -228,7 +265,7 @@ class WeaviateDocumentStore:
|
|
|
228
265
|
"""
|
|
229
266
|
Returns the number of documents present in the DocumentStore.
|
|
230
267
|
"""
|
|
231
|
-
total = self.
|
|
268
|
+
total = self.collection.aggregate.over_all(total_count=True).total_count
|
|
232
269
|
return total if total else 0
|
|
233
270
|
|
|
234
271
|
def _to_data_object(self, document: Document) -> Dict[str, Any]:
|
|
@@ -300,16 +337,16 @@ class WeaviateDocumentStore:
|
|
|
300
337
|
return Document.from_dict(document_data)
|
|
301
338
|
|
|
302
339
|
def _query(self) -> List[Dict[str, Any]]:
|
|
303
|
-
properties = [p.name for p in self.
|
|
340
|
+
properties = [p.name for p in self.collection.config.get().properties]
|
|
304
341
|
try:
|
|
305
|
-
result = self.
|
|
342
|
+
result = self.collection.iterator(include_vector=True, return_properties=properties)
|
|
306
343
|
except weaviate.exceptions.WeaviateQueryError as e:
|
|
307
344
|
msg = f"Failed to query documents in Weaviate. Error: {e.message}"
|
|
308
345
|
raise DocumentStoreError(msg) from e
|
|
309
346
|
return result
|
|
310
347
|
|
|
311
348
|
def _query_with_filters(self, filters: Dict[str, Any]) -> List[Dict[str, Any]]:
|
|
312
|
-
properties = [p.name for p in self.
|
|
349
|
+
properties = [p.name for p in self.collection.config.get().properties]
|
|
313
350
|
# When querying with filters we need to paginate using limit and offset as using
|
|
314
351
|
# a cursor with after is not possible. See the official docs:
|
|
315
352
|
# https://weaviate.io/developers/weaviate/api/graphql/additional-operators#cursor-with-after
|
|
@@ -325,7 +362,7 @@ class WeaviateDocumentStore:
|
|
|
325
362
|
# Keep querying until we get all documents matching the filters
|
|
326
363
|
while partial_result is None or len(partial_result.objects) == DEFAULT_QUERY_LIMIT:
|
|
327
364
|
try:
|
|
328
|
-
partial_result = self.
|
|
365
|
+
partial_result = self.collection.query.fetch_objects(
|
|
329
366
|
filters=convert_filters(filters),
|
|
330
367
|
include_vector=True,
|
|
331
368
|
limit=DEFAULT_QUERY_LIMIT,
|
|
@@ -349,6 +386,9 @@ class WeaviateDocumentStore:
|
|
|
349
386
|
:param filters: The filters to apply to the document list.
|
|
350
387
|
:returns: A list of Documents that match the given filters.
|
|
351
388
|
"""
|
|
389
|
+
if filters and "operator" not in filters and "conditions" not in filters:
|
|
390
|
+
filters = convert(filters)
|
|
391
|
+
|
|
352
392
|
result = []
|
|
353
393
|
if filters:
|
|
354
394
|
result = self._query_with_filters(filters)
|
|
@@ -363,7 +403,7 @@ class WeaviateDocumentStore:
|
|
|
363
403
|
Raises in case of errors.
|
|
364
404
|
"""
|
|
365
405
|
|
|
366
|
-
with self.
|
|
406
|
+
with self.client.batch.dynamic() as batch:
|
|
367
407
|
for doc in documents:
|
|
368
408
|
if not isinstance(doc, Document):
|
|
369
409
|
msg = f"Expected a Document, got '{type(doc)}' instead."
|
|
@@ -371,11 +411,11 @@ class WeaviateDocumentStore:
|
|
|
371
411
|
|
|
372
412
|
batch.add_object(
|
|
373
413
|
properties=self._to_data_object(doc),
|
|
374
|
-
collection=self.
|
|
414
|
+
collection=self.collection.name,
|
|
375
415
|
uuid=generate_uuid5(doc.id),
|
|
376
416
|
vector=doc.embedding,
|
|
377
417
|
)
|
|
378
|
-
if failed_objects := self.
|
|
418
|
+
if failed_objects := self.client.batch.failed_objects:
|
|
379
419
|
# We fallback to use the UUID if the _original_id is not present, this is just to be
|
|
380
420
|
mapped_objects = {}
|
|
381
421
|
for obj in failed_objects:
|
|
@@ -411,12 +451,12 @@ class WeaviateDocumentStore:
|
|
|
411
451
|
msg = f"Expected a Document, got '{type(doc)}' instead."
|
|
412
452
|
raise ValueError(msg)
|
|
413
453
|
|
|
414
|
-
if policy == DuplicatePolicy.SKIP and self.
|
|
454
|
+
if policy == DuplicatePolicy.SKIP and self.collection.data.exists(uuid=generate_uuid5(doc.id)):
|
|
415
455
|
# This Document already exists, we skip it
|
|
416
456
|
continue
|
|
417
457
|
|
|
418
458
|
try:
|
|
419
|
-
self.
|
|
459
|
+
self.collection.data.insert(
|
|
420
460
|
uuid=generate_uuid5(doc.id),
|
|
421
461
|
properties=self._to_data_object(doc),
|
|
422
462
|
vector=doc.embedding,
|
|
@@ -452,13 +492,13 @@ class WeaviateDocumentStore:
|
|
|
452
492
|
:param document_ids: The object_ids to delete.
|
|
453
493
|
"""
|
|
454
494
|
weaviate_ids = [generate_uuid5(doc_id) for doc_id in document_ids]
|
|
455
|
-
self.
|
|
495
|
+
self.collection.data.delete_many(where=weaviate.classes.query.Filter.by_id().contains_any(weaviate_ids))
|
|
456
496
|
|
|
457
497
|
def _bm25_retrieval(
|
|
458
498
|
self, query: str, filters: Optional[Dict[str, Any]] = None, top_k: Optional[int] = None
|
|
459
499
|
) -> List[Document]:
|
|
460
|
-
properties = [p.name for p in self.
|
|
461
|
-
result = self.
|
|
500
|
+
properties = [p.name for p in self.collection.config.get().properties]
|
|
501
|
+
result = self.collection.query.bm25(
|
|
462
502
|
query=query,
|
|
463
503
|
filters=convert_filters(filters) if filters else None,
|
|
464
504
|
limit=top_k,
|
|
@@ -482,8 +522,8 @@ class WeaviateDocumentStore:
|
|
|
482
522
|
msg = "Can't use 'distance' and 'certainty' parameters together"
|
|
483
523
|
raise ValueError(msg)
|
|
484
524
|
|
|
485
|
-
properties = [p.name for p in self.
|
|
486
|
-
result = self.
|
|
525
|
+
properties = [p.name for p in self.collection.config.get().properties]
|
|
526
|
+
result = self.collection.query.near_vector(
|
|
487
527
|
near_vector=query_embedding,
|
|
488
528
|
distance=distance,
|
|
489
529
|
certainty=certainty,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import base64
|
|
2
|
+
import os
|
|
2
3
|
import random
|
|
3
4
|
from typing import List
|
|
4
5
|
from unittest.mock import MagicMock, patch
|
|
@@ -16,6 +17,7 @@ from haystack.testing.document_store import (
|
|
|
16
17
|
FilterDocumentsTest,
|
|
17
18
|
WriteDocumentsTest,
|
|
18
19
|
)
|
|
20
|
+
from haystack.utils.auth import Secret
|
|
19
21
|
from haystack_integrations.document_stores.weaviate.auth import AuthApiKey
|
|
20
22
|
from haystack_integrations.document_stores.weaviate.document_store import (
|
|
21
23
|
DOCUMENT_COLLECTION_PROPERTIES,
|
|
@@ -26,8 +28,6 @@ from numpy import array_equal as np_array_equal
|
|
|
26
28
|
from numpy import float32 as np_float32
|
|
27
29
|
from pandas import DataFrame
|
|
28
30
|
from weaviate.collections.classes.data import DataObject
|
|
29
|
-
|
|
30
|
-
# from weaviate.auth import AuthApiKey as WeaviateAuthApiKey
|
|
31
31
|
from weaviate.config import AdditionalConfig, ConnectionConfig, Proxies, Timeout
|
|
32
32
|
from weaviate.embedded import (
|
|
33
33
|
DEFAULT_BINARY_PATH,
|
|
@@ -38,6 +38,12 @@ from weaviate.embedded import (
|
|
|
38
38
|
)
|
|
39
39
|
|
|
40
40
|
|
|
41
|
+
@patch("haystack_integrations.document_stores.weaviate.document_store.weaviate.WeaviateClient")
|
|
42
|
+
def test_init_is_lazy(_mock_client):
|
|
43
|
+
_ = WeaviateDocumentStore()
|
|
44
|
+
_mock_client.assert_not_called()
|
|
45
|
+
|
|
46
|
+
|
|
41
47
|
@pytest.mark.integration
|
|
42
48
|
class TestWeaviateDocumentStore(CountDocumentsTest, WriteDocumentsTest, DeleteDocumentsTest, FilterDocumentsTest):
|
|
43
49
|
@pytest.fixture
|
|
@@ -57,7 +63,7 @@ class TestWeaviateDocumentStore(CountDocumentsTest, WriteDocumentsTest, DeleteDo
|
|
|
57
63
|
collection_settings=collection_settings,
|
|
58
64
|
)
|
|
59
65
|
yield store
|
|
60
|
-
store.
|
|
66
|
+
store.client.collections.delete(collection_settings["class"])
|
|
61
67
|
|
|
62
68
|
@pytest.fixture
|
|
63
69
|
def filterable_docs(self) -> List[Document]:
|
|
@@ -150,12 +156,12 @@ class TestWeaviateDocumentStore(CountDocumentsTest, WriteDocumentsTest, DeleteDo
|
|
|
150
156
|
assert received_meta.get(key) == expected_meta.get(key)
|
|
151
157
|
|
|
152
158
|
@patch("haystack_integrations.document_stores.weaviate.document_store.weaviate.WeaviateClient")
|
|
153
|
-
def
|
|
159
|
+
def test_connection(self, mock_weaviate_client_class, monkeypatch):
|
|
154
160
|
mock_client = MagicMock()
|
|
155
161
|
mock_client.collections.exists.return_value = False
|
|
156
162
|
mock_weaviate_client_class.return_value = mock_client
|
|
157
163
|
monkeypatch.setenv("WEAVIATE_API_KEY", "my_api_key")
|
|
158
|
-
WeaviateDocumentStore(
|
|
164
|
+
ds = WeaviateDocumentStore(
|
|
159
165
|
collection_settings={"class": "My_collection"},
|
|
160
166
|
auth_client_secret=AuthApiKey(),
|
|
161
167
|
additional_headers={"X-HuggingFace-Api-Key": "MY_HUGGINGFACE_KEY"},
|
|
@@ -170,8 +176,11 @@ class TestWeaviateDocumentStore(CountDocumentsTest, WriteDocumentsTest, DeleteDo
|
|
|
170
176
|
),
|
|
171
177
|
)
|
|
172
178
|
|
|
173
|
-
#
|
|
179
|
+
# Trigger the actual database connection by accessing the `client` property so we
|
|
180
|
+
# can assert the setup was good
|
|
181
|
+
_ = ds.client
|
|
174
182
|
|
|
183
|
+
# Verify client is created with correct parameters
|
|
175
184
|
mock_weaviate_client_class.assert_called_once_with(
|
|
176
185
|
auth_client_secret=AuthApiKey().resolve_value(),
|
|
177
186
|
connection_params=None,
|
|
@@ -646,6 +655,15 @@ class TestWeaviateDocumentStore(CountDocumentsTest, WriteDocumentsTest, DeleteDo
|
|
|
646
655
|
with pytest.raises(ValueError):
|
|
647
656
|
document_store._embedding_retrieval(query_embedding=[], distance=0.1, certainty=0.1)
|
|
648
657
|
|
|
658
|
+
def test_filter_documents_with_legacy_filters(self, document_store):
|
|
659
|
+
docs = []
|
|
660
|
+
for index in range(10):
|
|
661
|
+
docs.append(Document(content="This is some content", meta={"index": index}))
|
|
662
|
+
document_store.write_documents(docs)
|
|
663
|
+
result = document_store.filter_documents({"content": {"$eq": "This is some content"}})
|
|
664
|
+
|
|
665
|
+
assert len(result) == 10
|
|
666
|
+
|
|
649
667
|
def test_filter_documents_below_default_limit(self, document_store):
|
|
650
668
|
docs = []
|
|
651
669
|
for index in range(9998):
|
|
@@ -664,3 +682,39 @@ class TestWeaviateDocumentStore(CountDocumentsTest, WriteDocumentsTest, DeleteDo
|
|
|
664
682
|
document_store.write_documents(docs)
|
|
665
683
|
with pytest.raises(DocumentStoreError):
|
|
666
684
|
document_store.filter_documents({"field": "content", "operator": "==", "value": "This is some content"})
|
|
685
|
+
|
|
686
|
+
def test_schema_class_name_conversion_preserves_pascal_case(self):
|
|
687
|
+
collection_settings = {"class": "CaseDocument"}
|
|
688
|
+
doc_score = WeaviateDocumentStore(
|
|
689
|
+
url="http://localhost:8080",
|
|
690
|
+
collection_settings=collection_settings,
|
|
691
|
+
)
|
|
692
|
+
assert doc_score._collection_settings["class"] == "CaseDocument"
|
|
693
|
+
|
|
694
|
+
collection_settings = {"class": "lower_case_name"}
|
|
695
|
+
doc_score = WeaviateDocumentStore(
|
|
696
|
+
url="http://localhost:8080",
|
|
697
|
+
collection_settings=collection_settings,
|
|
698
|
+
)
|
|
699
|
+
assert doc_score._collection_settings["class"] == "Lower_case_name"
|
|
700
|
+
|
|
701
|
+
@pytest.mark.skipif(
|
|
702
|
+
not os.environ.get("WEAVIATE_API_KEY", None) and not os.environ.get("WEAVIATE_CLOUD_CLUSTER_URL", None),
|
|
703
|
+
reason="Both WEAVIATE_API_KEY and WEAVIATE_CLOUD_CLUSTER_URL are not set. Skipping test.",
|
|
704
|
+
)
|
|
705
|
+
def test_connect_to_weaviate_cloud(self):
|
|
706
|
+
document_store = WeaviateDocumentStore(
|
|
707
|
+
url=os.environ.get("WEAVIATE_CLOUD_CLUSTER_URL"),
|
|
708
|
+
auth_client_secret=AuthApiKey(api_key=Secret.from_env_var("WEAVIATE_API_KEY")),
|
|
709
|
+
)
|
|
710
|
+
assert document_store.client
|
|
711
|
+
|
|
712
|
+
def test_connect_to_local(self):
|
|
713
|
+
document_store = WeaviateDocumentStore(
|
|
714
|
+
url="http://localhost:8080",
|
|
715
|
+
)
|
|
716
|
+
assert document_store.client
|
|
717
|
+
|
|
718
|
+
def test_connect_to_embedded(self):
|
|
719
|
+
document_store = WeaviateDocumentStore(embedded_options=EmbeddedOptions())
|
|
720
|
+
assert document_store.client
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|