weaviate-haystack 4.0.2__tar.gz → 5.0.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 (23) hide show
  1. {weaviate_haystack-4.0.2 → weaviate_haystack-5.0.0}/CHANGELOG.md +6 -0
  2. {weaviate_haystack-4.0.2 → weaviate_haystack-5.0.0}/PKG-INFO +4 -4
  3. {weaviate_haystack-4.0.2 → weaviate_haystack-5.0.0}/pyproject.toml +3 -1
  4. {weaviate_haystack-4.0.2 → weaviate_haystack-5.0.0}/src/haystack_integrations/document_stores/weaviate/_filters.py +4 -7
  5. {weaviate_haystack-4.0.2 → weaviate_haystack-5.0.0}/src/haystack_integrations/document_stores/weaviate/document_store.py +25 -6
  6. {weaviate_haystack-4.0.2 → weaviate_haystack-5.0.0}/tests/test_bm25_retriever.py +0 -3
  7. {weaviate_haystack-4.0.2 → weaviate_haystack-5.0.0}/tests/test_document_store.py +29 -66
  8. {weaviate_haystack-4.0.2 → weaviate_haystack-5.0.0}/tests/test_embedding_retriever.py +0 -3
  9. {weaviate_haystack-4.0.2 → weaviate_haystack-5.0.0}/.gitignore +0 -0
  10. {weaviate_haystack-4.0.2 → weaviate_haystack-5.0.0}/LICENSE.txt +0 -0
  11. {weaviate_haystack-4.0.2 → weaviate_haystack-5.0.0}/README.md +0 -0
  12. {weaviate_haystack-4.0.2 → weaviate_haystack-5.0.0}/docker-compose.yml +0 -0
  13. {weaviate_haystack-4.0.2 → weaviate_haystack-5.0.0}/pydoc/config.yml +0 -0
  14. {weaviate_haystack-4.0.2 → weaviate_haystack-5.0.0}/src/haystack_integrations/components/retrievers/weaviate/__init__.py +0 -0
  15. {weaviate_haystack-4.0.2 → weaviate_haystack-5.0.0}/src/haystack_integrations/components/retrievers/weaviate/bm25_retriever.py +0 -0
  16. {weaviate_haystack-4.0.2 → weaviate_haystack-5.0.0}/src/haystack_integrations/components/retrievers/weaviate/embedding_retriever.py +0 -0
  17. {weaviate_haystack-4.0.2 → weaviate_haystack-5.0.0}/src/haystack_integrations/document_stores/weaviate/__init__.py +1 -1
  18. {weaviate_haystack-4.0.2 → weaviate_haystack-5.0.0}/src/haystack_integrations/document_stores/weaviate/auth.py +0 -0
  19. {weaviate_haystack-4.0.2 → weaviate_haystack-5.0.0}/tests/__init__.py +0 -0
  20. {weaviate_haystack-4.0.2 → weaviate_haystack-5.0.0}/tests/conftest.py +0 -0
  21. {weaviate_haystack-4.0.2 → weaviate_haystack-5.0.0}/tests/test_auth.py +0 -0
  22. {weaviate_haystack-4.0.2 → weaviate_haystack-5.0.0}/tests/test_files/robot1.jpg +0 -0
  23. {weaviate_haystack-4.0.2 → weaviate_haystack-5.0.0}/tests/test_filters.py +0 -0
@@ -1,5 +1,11 @@
1
1
  # Changelog
2
2
 
3
+ ## [integrations/weaviate-v4.0.2] - 2024-11-13
4
+
5
+ ### 🐛 Bug Fixes
6
+
7
+ - Dependency for weaviate document store (#1186)
8
+
3
9
  ## [integrations/weaviate-v4.0.1] - 2024-11-11
4
10
 
5
11
  ## [integrations/weaviate-v4.0.0] - 2024-10-18
@@ -1,16 +1,16 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: weaviate-haystack
3
- Version: 4.0.2
3
+ Version: 5.0.0
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
7
7
  Project-URL: Issues, https://github.com/deepset-ai/haystack-core-integrations/issues
8
8
  Author-email: deepset GmbH <info@deepset.ai>
9
- License: Apache-2.0
9
+ License-Expression: Apache-2.0
10
+ License-File: LICENSE.txt
10
11
  Classifier: Development Status :: 4 - Beta
11
12
  Classifier: License :: OSI Approved :: Apache Software License
12
13
  Classifier: Programming Language :: Python
13
- Classifier: Programming Language :: Python :: 3.8
14
14
  Classifier: Programming Language :: Python :: 3.9
15
15
  Classifier: Programming Language :: Python :: 3.10
16
16
  Classifier: Programming Language :: Python :: 3.11
@@ -15,7 +15,6 @@ classifiers = [
15
15
  "License :: OSI Approved :: Apache Software License",
16
16
  "Development Status :: 4 - Beta",
17
17
  "Programming Language :: Python",
18
- "Programming Language :: Python :: 3.8",
19
18
  "Programming Language :: Python :: 3.9",
20
19
  "Programming Language :: Python :: 3.10",
21
20
  "Programming Language :: Python :: 3.11",
@@ -160,3 +159,6 @@ module = [
160
159
  "grpc",
161
160
  ]
162
161
  ignore_missing_imports = true
162
+
163
+ [tool.pytest.ini_options]
164
+ markers = ["integration: integration tests"]
@@ -6,7 +6,6 @@ from typing import Any, Dict
6
6
 
7
7
  from dateutil import parser
8
8
  from haystack.errors import FilterError
9
- from pandas import DataFrame
10
9
 
11
10
  import weaviate
12
11
  from weaviate.collections.classes.filters import Filter, FilterReturn
@@ -129,7 +128,7 @@ def _greater_than(field: str, value: Any) -> FilterReturn:
129
128
  "Strings are only comparable if they are ISO formatted dates."
130
129
  )
131
130
  raise FilterError(msg) from exc
132
- if type(value) in [list, DataFrame]:
131
+ if isinstance(value, list):
133
132
  msg = f"Filter value can't be of type {type(value)} using operators '>', '>=', '<', '<='"
134
133
  raise FilterError(msg)
135
134
  return weaviate.classes.query.Filter.by_property(field).greater_than(_handle_date(value))
@@ -151,7 +150,7 @@ def _greater_than_equal(field: str, value: Any) -> FilterReturn:
151
150
  "Strings are only comparable if they are ISO formatted dates."
152
151
  )
153
152
  raise FilterError(msg) from exc
154
- if type(value) in [list, DataFrame]:
153
+ if isinstance(value, list):
155
154
  msg = f"Filter value can't be of type {type(value)} using operators '>', '>=', '<', '<='"
156
155
  raise FilterError(msg)
157
156
  return weaviate.classes.query.Filter.by_property(field).greater_or_equal(_handle_date(value))
@@ -173,7 +172,7 @@ def _less_than(field: str, value: Any) -> FilterReturn:
173
172
  "Strings are only comparable if they are ISO formatted dates."
174
173
  )
175
174
  raise FilterError(msg) from exc
176
- if type(value) in [list, DataFrame]:
175
+ if isinstance(value, list):
177
176
  msg = f"Filter value can't be of type {type(value)} using operators '>', '>=', '<', '<='"
178
177
  raise FilterError(msg)
179
178
  return weaviate.classes.query.Filter.by_property(field).less_than(_handle_date(value))
@@ -195,7 +194,7 @@ def _less_than_equal(field: str, value: Any) -> FilterReturn:
195
194
  "Strings are only comparable if they are ISO formatted dates."
196
195
  )
197
196
  raise FilterError(msg) from exc
198
- if type(value) in [list, DataFrame]:
197
+ if isinstance(value, list):
199
198
  msg = f"Filter value can't be of type {type(value)} using operators '>', '>=', '<', '<='"
200
199
  raise FilterError(msg)
201
200
  return weaviate.classes.query.Filter.by_property(field).less_or_equal(_handle_date(value))
@@ -248,8 +247,6 @@ def _parse_comparison_condition(condition: Dict[str, Any]) -> FilterReturn:
248
247
  raise FilterError(msg)
249
248
  operator: str = condition["operator"]
250
249
  value: Any = condition["value"]
251
- if isinstance(value, DataFrame):
252
- value = value.to_json()
253
250
 
254
251
  return COMPARISON_OPERATORS[operator](field, value)
255
252
 
@@ -4,10 +4,10 @@
4
4
  import base64
5
5
  import datetime
6
6
  import json
7
- import logging
8
7
  from dataclasses import asdict
9
8
  from typing import Any, Dict, List, Optional
10
9
 
10
+ from haystack import logging
11
11
  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
@@ -39,7 +39,6 @@ logger = logging.getLogger(__name__)
39
39
  DOCUMENT_COLLECTION_PROPERTIES = [
40
40
  {"name": "_original_id", "dataType": ["text"]},
41
41
  {"name": "content", "dataType": ["text"]},
42
- {"name": "dataframe", "dataType": ["text"]},
43
42
  {"name": "blob_data", "dataType": ["blob"]},
44
43
  {"name": "blob_mime_type", "dataType": ["text"]},
45
44
  {"name": "score", "dataType": ["number"]},
@@ -105,7 +104,6 @@ class WeaviateDocumentStore:
105
104
  properties:
106
105
  - _original_id: text
107
106
  - content: text
108
- - dataframe: text
109
107
  - blob_data: blob
110
108
  - blob_mime_type: text
111
109
  - score: number
@@ -291,17 +289,28 @@ class WeaviateDocumentStore:
291
289
  if "_split_overlap" in data:
292
290
  data.pop("_split_overlap")
293
291
  logger.warning(
294
- "Document %s has the unsupported `_split_overlap` meta field. It will be ignored.", data["_original_id"]
292
+ "Document {id} has the unsupported `_split_overlap` meta field. It will be ignored.",
293
+ id=data["_original_id"],
295
294
  )
296
295
 
296
+ if "dataframe" in data:
297
+ dataframe = data.pop("dataframe")
298
+ if dataframe:
299
+ logger.warning(
300
+ "Document {id} has the `dataframe` field set. "
301
+ "WeaviateDocumentStore no longer supports dataframes and this field will be ignored. "
302
+ "The `dataframe` field will soon be removed from Haystack Document.",
303
+ id=data["_original_id"],
304
+ )
305
+
297
306
  if "sparse_embedding" in data:
298
307
  sparse_embedding = data.pop("sparse_embedding", None)
299
308
  if sparse_embedding:
300
309
  logger.warning(
301
- "Document %s has the `sparse_embedding` field set,"
310
+ "Document {id} has the `sparse_embedding` field set,"
302
311
  "but storing sparse embeddings in Weaviate is not currently supported."
303
312
  "The `sparse_embedding` field will be ignored.",
304
- data["_original_id"],
313
+ id=data["_original_id"],
305
314
  )
306
315
 
307
316
  return data
@@ -329,6 +338,16 @@ class WeaviateDocumentStore:
329
338
  document_data.pop("blob_data", None)
330
339
  document_data.pop("blob_mime_type", None)
331
340
 
341
+ if "dataframe" in document_data:
342
+ dataframe = document_data.pop("dataframe")
343
+ if dataframe:
344
+ logger.warning(
345
+ "Document {id} has the `dataframe` field set. "
346
+ "WeaviateDocumentStore no longer supports dataframes and this field will be ignored. "
347
+ "The `dataframe` field will soon be removed from Haystack Document.",
348
+ id=document_data["id"],
349
+ )
350
+
332
351
  for key, value in document_data.items():
333
352
  if isinstance(value, datetime.datetime):
334
353
  document_data[key] = value.strftime("%Y-%m-%dT%H:%M:%SZ")
@@ -46,7 +46,6 @@ def test_to_dict(_mock_weaviate):
46
46
  "properties": [
47
47
  {"name": "_original_id", "dataType": ["text"]},
48
48
  {"name": "content", "dataType": ["text"]},
49
- {"name": "dataframe", "dataType": ["text"]},
50
49
  {"name": "blob_data", "dataType": ["blob"]},
51
50
  {"name": "blob_mime_type", "dataType": ["text"]},
52
51
  {"name": "score", "dataType": ["number"]},
@@ -81,7 +80,6 @@ def test_from_dict(_mock_weaviate):
81
80
  "properties": [
82
81
  {"name": "_original_id", "dataType": ["text"]},
83
82
  {"name": "content", "dataType": ["text"]},
84
- {"name": "dataframe", "dataType": ["text"]},
85
83
  {"name": "blob_data", "dataType": ["blob"]},
86
84
  {"name": "blob_mime_type", "dataType": ["text"]},
87
85
  {"name": "score", "dataType": ["number"]},
@@ -119,7 +117,6 @@ def test_from_dict_no_filter_policy(_mock_weaviate):
119
117
  "properties": [
120
118
  {"name": "_original_id", "dataType": ["text"]},
121
119
  {"name": "content", "dataType": ["text"]},
122
- {"name": "dataframe", "dataType": ["text"]},
123
120
  {"name": "blob_data", "dataType": ["blob"]},
124
121
  {"name": "blob_mime_type", "dataType": ["text"]},
125
122
  {"name": "score", "dataType": ["number"]},
@@ -4,7 +4,6 @@
4
4
 
5
5
  import base64
6
6
  import os
7
- import random
8
7
  from typing import List
9
8
  from unittest.mock import MagicMock, patch
10
9
 
@@ -14,12 +13,11 @@ from haystack.dataclasses.byte_stream import ByteStream
14
13
  from haystack.dataclasses.document import Document
15
14
  from haystack.document_stores.errors import DocumentStoreError
16
15
  from haystack.testing.document_store import (
17
- TEST_EMBEDDING_1,
18
- TEST_EMBEDDING_2,
19
16
  CountDocumentsTest,
20
17
  DeleteDocumentsTest,
21
18
  FilterDocumentsTest,
22
19
  WriteDocumentsTest,
20
+ create_filterable_docs,
23
21
  )
24
22
  from haystack.utils.auth import Secret
25
23
  from numpy import array as np_array
@@ -78,60 +76,10 @@ class TestWeaviateDocumentStore(CountDocumentsTest, WriteDocumentsTest, DeleteDo
78
76
  Weaviate forces RFC 3339 date strings.
79
77
  The original fixture uses ISO 8601 date strings.
80
78
  """
81
- documents = []
82
- for i in range(3):
83
- documents.append(
84
- Document(
85
- content=f"A Foo Document {i}",
86
- meta={
87
- "name": f"name_{i}",
88
- "page": "100",
89
- "chapter": "intro",
90
- "number": 2,
91
- "date": "1969-07-21T20:17:40Z",
92
- },
93
- embedding=[random.random() for _ in range(768)], # noqa: S311
94
- )
95
- )
96
- documents.append(
97
- Document(
98
- content=f"A Bar Document {i}",
99
- meta={
100
- "name": f"name_{i}",
101
- "page": "123",
102
- "chapter": "abstract",
103
- "number": -2,
104
- "date": "1972-12-11T19:54:58Z",
105
- },
106
- embedding=[random.random() for _ in range(768)], # noqa: S311
107
- )
108
- )
109
- documents.append(
110
- Document(
111
- content=f"A Foobar Document {i}",
112
- meta={
113
- "name": f"name_{i}",
114
- "page": "90",
115
- "chapter": "conclusion",
116
- "number": -10,
117
- "date": "1989-11-09T17:53:00Z",
118
- },
119
- embedding=[random.random() for _ in range(768)], # noqa: S311
120
- )
121
- )
122
- documents.append(
123
- Document(
124
- content=f"Document {i} without embedding",
125
- meta={"name": f"name_{i}", "no_embedding": True, "chapter": "conclusion"},
126
- )
127
- )
128
- documents.append(Document(dataframe=DataFrame([i]), meta={"name": f"table_doc_{i}"}))
129
- documents.append(
130
- Document(content=f"Doc {i} with zeros emb", meta={"name": "zeros_doc"}, embedding=TEST_EMBEDDING_1)
131
- )
132
- documents.append(
133
- Document(content=f"Doc {i} with ones emb", meta={"name": "ones_doc"}, embedding=TEST_EMBEDDING_2)
134
- )
79
+ documents = create_filterable_docs()
80
+ for i in range(len(documents)):
81
+ if date := documents[i].meta.get("date"):
82
+ documents[i].meta["date"] = f"{date}Z"
135
83
  return documents
136
84
 
137
85
  def assert_documents_are_equal(self, received: List[Document], expected: List[Document]):
@@ -238,7 +186,6 @@ class TestWeaviateDocumentStore(CountDocumentsTest, WriteDocumentsTest, DeleteDo
238
186
  "properties": [
239
187
  {"name": "_original_id", "dataType": ["text"]},
240
188
  {"name": "content", "dataType": ["text"]},
241
- {"name": "dataframe", "dataType": ["text"]},
242
189
  {"name": "blob_data", "dataType": ["blob"]},
243
190
  {"name": "blob_mime_type", "dataType": ["text"]},
244
191
  {"name": "score", "dataType": ["number"]},
@@ -320,7 +267,6 @@ class TestWeaviateDocumentStore(CountDocumentsTest, WriteDocumentsTest, DeleteDo
320
267
  "properties": [
321
268
  {"name": "_original_id", "dataType": ["text"]},
322
269
  {"name": "content", "dataType": ["text"]},
323
- {"name": "dataframe", "dataType": ["text"]},
324
270
  {"name": "blob_data", "dataType": ["blob"]},
325
271
  {"name": "blob_mime_type", "dataType": ["text"]},
326
272
  {"name": "score", "dataType": ["number"]},
@@ -348,7 +294,6 @@ class TestWeaviateDocumentStore(CountDocumentsTest, WriteDocumentsTest, DeleteDo
348
294
  assert data == {
349
295
  "_original_id": doc.id,
350
296
  "content": doc.content,
351
- "dataframe": None,
352
297
  "score": None,
353
298
  }
354
299
 
@@ -365,11 +310,20 @@ class TestWeaviateDocumentStore(CountDocumentsTest, WriteDocumentsTest, DeleteDo
365
310
  "content": doc.content,
366
311
  "blob_data": base64.b64encode(image.data).decode(),
367
312
  "blob_mime_type": "image/jpeg",
368
- "dataframe": None,
369
313
  "score": None,
370
314
  "key": "value",
371
315
  }
372
316
 
317
+ def test_to_data_object_skips_dataframe(self, document_store):
318
+ doc = Document(id="test_id", content="test content")
319
+ doc.dataframe = DataFrame([{"a": 1, "b": 2}, {"a": 3, "b": 4}])
320
+
321
+ data = document_store._to_data_object(doc)
322
+
323
+ assert data["_original_id"] == "test_id"
324
+ assert data["content"] == "test content"
325
+ assert "dataframe" not in data
326
+
373
327
  def test_to_document(self, document_store, test_files_path):
374
328
  image = ByteStream.from_file_path(test_files_path / "robot1.jpg", mime_type="image/jpeg")
375
329
  data = DataObject(
@@ -378,7 +332,6 @@ class TestWeaviateDocumentStore(CountDocumentsTest, WriteDocumentsTest, DeleteDo
378
332
  "content": "some content",
379
333
  "blob_data": base64.b64encode(image.data).decode(),
380
334
  "blob_mime_type": "image/jpeg",
381
- "dataframe": None,
382
335
  "score": None,
383
336
  "key": "value",
384
337
  },
@@ -393,6 +346,20 @@ class TestWeaviateDocumentStore(CountDocumentsTest, WriteDocumentsTest, DeleteDo
393
346
  assert doc.score is None
394
347
  assert doc.meta == {"key": "value"}
395
348
 
349
+ def test_to_document_skips_dataframe(self, document_store):
350
+ data = DataObject(
351
+ properties={
352
+ "_original_id": "test_id",
353
+ "content": "test content",
354
+ "dataframe": {"a": [1, 2, 3]},
355
+ }
356
+ )
357
+
358
+ doc = document_store._to_document(data)
359
+ assert doc.id == "test_id"
360
+ assert doc.content == "test content"
361
+ assert not hasattr(doc, "dataframe") or doc.dataframe is None
362
+
396
363
  def test_write_documents(self, document_store):
397
364
  """
398
365
  Test write_documents() with default policy overwrites existing documents.
@@ -504,10 +471,6 @@ class TestWeaviateDocumentStore(CountDocumentsTest, WriteDocumentsTest, DeleteDo
504
471
  ],
505
472
  )
506
473
 
507
- @pytest.mark.skip(reason="Weaviate for some reason is not returning what we expect")
508
- def test_comparison_not_equal_with_dataframe(self, document_store, filterable_docs):
509
- return super().test_comparison_not_equal_with_dataframe(document_store, filterable_docs)
510
-
511
474
  def test_meta_split_overlap_is_skipped(self, document_store):
512
475
  doc = Document(
513
476
  content="The moonlight shimmered ",
@@ -56,7 +56,6 @@ def test_to_dict(_mock_weaviate):
56
56
  "properties": [
57
57
  {"name": "_original_id", "dataType": ["text"]},
58
58
  {"name": "content", "dataType": ["text"]},
59
- {"name": "dataframe", "dataType": ["text"]},
60
59
  {"name": "blob_data", "dataType": ["blob"]},
61
60
  {"name": "blob_mime_type", "dataType": ["text"]},
62
61
  {"name": "score", "dataType": ["number"]},
@@ -93,7 +92,6 @@ def test_from_dict(_mock_weaviate):
93
92
  "properties": [
94
93
  {"name": "_original_id", "dataType": ["text"]},
95
94
  {"name": "content", "dataType": ["text"]},
96
- {"name": "dataframe", "dataType": ["text"]},
97
95
  {"name": "blob_data", "dataType": ["blob"]},
98
96
  {"name": "blob_mime_type", "dataType": ["text"]},
99
97
  {"name": "score", "dataType": ["number"]},
@@ -135,7 +133,6 @@ def test_from_dict_no_filter_policy(_mock_weaviate):
135
133
  "properties": [
136
134
  {"name": "_original_id", "dataType": ["text"]},
137
135
  {"name": "content", "dataType": ["text"]},
138
- {"name": "dataframe", "dataType": ["text"]},
139
136
  {"name": "blob_data", "dataType": ["blob"]},
140
137
  {"name": "blob_mime_type", "dataType": ["text"]},
141
138
  {"name": "score", "dataType": ["number"]},
@@ -5,10 +5,10 @@ from .auth import AuthApiKey, AuthBearerToken, AuthClientCredentials, AuthClient
5
5
  from .document_store import WeaviateDocumentStore
6
6
 
7
7
  __all__ = [
8
- "WeaviateDocumentStore",
9
8
  "AuthApiKey",
10
9
  "AuthBearerToken",
11
10
  "AuthClientCredentials",
12
11
  "AuthClientPassword",
13
12
  "AuthCredentials",
13
+ "WeaviateDocumentStore",
14
14
  ]