qdrant-haystack 10.3.1__tar.gz → 10.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.
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/CHANGELOG.md +23 -0
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/PKG-INFO +1 -1
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/pyproject.toml +1 -0
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/src/haystack_integrations/components/retrievers/qdrant/retriever.py +36 -0
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/src/haystack_integrations/document_stores/qdrant/document_store.py +19 -0
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/tests/test_document_store.py +33 -0
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/tests/test_document_store_async.py +34 -1
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/tests/test_embedding_retriever.py +20 -0
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/tests/test_hybrid_retriever.py +21 -1
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/tests/test_sparse_embedding_retriever.py +20 -0
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/.gitignore +0 -0
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/LICENSE.txt +0 -0
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/README.md +0 -0
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/examples/embedding_retrieval.py +0 -0
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/pydoc/config_docusaurus.yml +0 -0
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/src/haystack_integrations/components/retrievers/py.typed +0 -0
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/src/haystack_integrations/components/retrievers/qdrant/__init__.py +0 -0
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/src/haystack_integrations/document_stores/py.typed +0 -0
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/src/haystack_integrations/document_stores/qdrant/__init__.py +0 -0
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/src/haystack_integrations/document_stores/qdrant/converters.py +0 -0
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/src/haystack_integrations/document_stores/qdrant/filters.py +0 -0
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/src/haystack_integrations/document_stores/qdrant/migrate_to_sparse.py +0 -0
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/tests/__init__.py +0 -0
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/tests/conftest.py +0 -0
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/tests/test_converters.py +0 -0
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/tests/test_dict_converters.py +0 -0
- {qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/tests/test_filters.py +0 -0
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [integrations/qdrant-v10.3.1] - 2026-07-06
|
|
4
|
+
|
|
5
|
+
### 🐛 Bug Fixes
|
|
6
|
+
|
|
7
|
+
- Replace in-place dataclass mutations in document stores (#3114)
|
|
8
|
+
|
|
9
|
+
### 📚 Documentation
|
|
10
|
+
|
|
11
|
+
- Replace old haystack core imports with haystack_integrations paths (#3545)
|
|
12
|
+
|
|
13
|
+
### 🧪 Testing
|
|
14
|
+
|
|
15
|
+
- Track test coverage for all integrations (#3065)
|
|
16
|
+
- Mark some tests as integration in Faiss and Qdrant (#3076)
|
|
17
|
+
- Qdrant - add unit tests (#3183)
|
|
18
|
+
- Qdrant - add more unit tests (#3221)
|
|
19
|
+
- *(qdrant)* Use async DocumentStore mixin tests (#3093)
|
|
20
|
+
|
|
21
|
+
### 🧹 Chores
|
|
22
|
+
|
|
23
|
+
- Enforce ruff docstring rules in integrations 31-40 (openrouter, opensearch, optimum, paddleocr, pgvector, pinecone, pyversity, qdrant, ragas, snowflake) (#3011)
|
|
24
|
+
|
|
25
|
+
|
|
3
26
|
## [integrations/qdrant-v10.3.0] - 2026-03-23
|
|
4
27
|
|
|
5
28
|
### 📚 Documentation
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: qdrant-haystack
|
|
3
|
-
Version: 10.
|
|
3
|
+
Version: 10.4.0
|
|
4
4
|
Summary: An integration of Qdrant ANN vector database backend 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/qdrant/README.md
|
|
@@ -130,6 +130,18 @@ class QdrantEmbeddingRetriever:
|
|
|
130
130
|
data["init_parameters"]["filter_policy"] = FilterPolicy.from_str(filter_policy)
|
|
131
131
|
return default_from_dict(cls, data)
|
|
132
132
|
|
|
133
|
+
def close(self) -> None:
|
|
134
|
+
"""
|
|
135
|
+
Release the synchronous resources of the underlying Document Store.
|
|
136
|
+
"""
|
|
137
|
+
self._document_store.close()
|
|
138
|
+
|
|
139
|
+
async def close_async(self) -> None:
|
|
140
|
+
"""
|
|
141
|
+
Release the asynchronous resources of the underlying Document Store.
|
|
142
|
+
"""
|
|
143
|
+
await self._document_store.close_async()
|
|
144
|
+
|
|
133
145
|
@component.output_types(documents=list[Document])
|
|
134
146
|
def run(
|
|
135
147
|
self,
|
|
@@ -358,6 +370,18 @@ class QdrantSparseEmbeddingRetriever:
|
|
|
358
370
|
data["init_parameters"]["filter_policy"] = FilterPolicy.from_str(filter_policy)
|
|
359
371
|
return default_from_dict(cls, data)
|
|
360
372
|
|
|
373
|
+
def close(self) -> None:
|
|
374
|
+
"""
|
|
375
|
+
Release the synchronous resources of the underlying Document Store.
|
|
376
|
+
"""
|
|
377
|
+
self._document_store.close()
|
|
378
|
+
|
|
379
|
+
async def close_async(self) -> None:
|
|
380
|
+
"""
|
|
381
|
+
Release the asynchronous resources of the underlying Document Store.
|
|
382
|
+
"""
|
|
383
|
+
await self._document_store.close_async()
|
|
384
|
+
|
|
361
385
|
@component.output_types(documents=list[Document])
|
|
362
386
|
def run(
|
|
363
387
|
self,
|
|
@@ -596,6 +620,18 @@ class QdrantHybridRetriever:
|
|
|
596
620
|
data["init_parameters"]["filter_policy"] = FilterPolicy.from_str(filter_policy)
|
|
597
621
|
return default_from_dict(cls, data)
|
|
598
622
|
|
|
623
|
+
def close(self) -> None:
|
|
624
|
+
"""
|
|
625
|
+
Release the synchronous resources of the underlying Document Store.
|
|
626
|
+
"""
|
|
627
|
+
self._document_store.close()
|
|
628
|
+
|
|
629
|
+
async def close_async(self) -> None:
|
|
630
|
+
"""
|
|
631
|
+
Release the asynchronous resources of the underlying Document Store.
|
|
632
|
+
"""
|
|
633
|
+
await self._document_store.close_async()
|
|
634
|
+
|
|
599
635
|
@component.output_types(documents=list[Document])
|
|
600
636
|
def run(
|
|
601
637
|
self,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import inspect
|
|
2
2
|
from collections.abc import AsyncGenerator, Generator
|
|
3
|
+
from contextlib import suppress
|
|
3
4
|
from dataclasses import replace
|
|
4
5
|
from itertools import islice
|
|
5
6
|
from typing import Any, ClassVar, cast
|
|
@@ -301,6 +302,24 @@ class QdrantDocumentStore:
|
|
|
301
302
|
self.payload_fields_to_index,
|
|
302
303
|
)
|
|
303
304
|
|
|
305
|
+
def close(self) -> None:
|
|
306
|
+
"""
|
|
307
|
+
Release the associated synchronous resources.
|
|
308
|
+
"""
|
|
309
|
+
if self._client is not None:
|
|
310
|
+
with suppress(Exception):
|
|
311
|
+
self._client.close()
|
|
312
|
+
self._client = None
|
|
313
|
+
|
|
314
|
+
async def close_async(self) -> None:
|
|
315
|
+
"""
|
|
316
|
+
Release the associated asynchronous resources.
|
|
317
|
+
"""
|
|
318
|
+
if self._async_client is not None:
|
|
319
|
+
with suppress(Exception):
|
|
320
|
+
await self._async_client.close()
|
|
321
|
+
self._async_client = None
|
|
322
|
+
|
|
304
323
|
def count_documents(self) -> int:
|
|
305
324
|
"""
|
|
306
325
|
Returns the number of documents present in the Document Store.
|
|
@@ -370,6 +370,29 @@ class TestQdrantDocumentStoreUnit:
|
|
|
370
370
|
):
|
|
371
371
|
assert getattr(document_store, method_name)(*args) == expected
|
|
372
372
|
|
|
373
|
+
def test_close(self):
|
|
374
|
+
document_store = QdrantDocumentStore(location=":memory:")
|
|
375
|
+
mock_client = MagicMock()
|
|
376
|
+
document_store._client = mock_client
|
|
377
|
+
|
|
378
|
+
document_store.close()
|
|
379
|
+
|
|
380
|
+
mock_client.close.assert_called_once()
|
|
381
|
+
assert document_store._client is None
|
|
382
|
+
|
|
383
|
+
document_store.close()
|
|
384
|
+
mock_client.close.assert_called_once()
|
|
385
|
+
|
|
386
|
+
def test_close_is_exception_safe(self):
|
|
387
|
+
document_store = QdrantDocumentStore(location=":memory:")
|
|
388
|
+
mock_client = MagicMock()
|
|
389
|
+
mock_client.close.side_effect = RuntimeError("boom")
|
|
390
|
+
document_store._client = mock_client
|
|
391
|
+
|
|
392
|
+
document_store.close()
|
|
393
|
+
|
|
394
|
+
assert document_store._client is None
|
|
395
|
+
|
|
373
396
|
|
|
374
397
|
@pytest.mark.integration
|
|
375
398
|
class TestQdrantDocumentStore(
|
|
@@ -409,6 +432,16 @@ class TestQdrantDocumentStore(
|
|
|
409
432
|
# Check that the sets are equal, meaning the content and IDs match regardless of order
|
|
410
433
|
assert {doc.id for doc in received} == {doc.id for doc in expected}
|
|
411
434
|
|
|
435
|
+
def test_close_and_reopen(self, document_store: QdrantDocumentStore):
|
|
436
|
+
assert document_store.count_documents() == 0
|
|
437
|
+
assert document_store._client is not None
|
|
438
|
+
|
|
439
|
+
document_store.close()
|
|
440
|
+
|
|
441
|
+
assert document_store._client is None
|
|
442
|
+
assert document_store.count_documents() == 0
|
|
443
|
+
assert document_store._client is not None
|
|
444
|
+
|
|
412
445
|
def test_prepare_client_params_no_mutability(self):
|
|
413
446
|
metadata = {"key": "value"}
|
|
414
447
|
doc_store = QdrantDocumentStore(
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from unittest.mock import MagicMock, patch
|
|
1
|
+
from unittest.mock import AsyncMock, MagicMock, patch
|
|
2
2
|
|
|
3
3
|
import pytest
|
|
4
4
|
import pytest_asyncio
|
|
@@ -162,6 +162,29 @@ class TestQdrantDocumentStoreAsyncUnit:
|
|
|
162
162
|
):
|
|
163
163
|
assert await getattr(document_store, method_name)(*args) == expected
|
|
164
164
|
|
|
165
|
+
async def test_close_async(self):
|
|
166
|
+
document_store = QdrantDocumentStore(location=":memory:")
|
|
167
|
+
mock_client = AsyncMock()
|
|
168
|
+
document_store._async_client = mock_client
|
|
169
|
+
|
|
170
|
+
await document_store.close_async()
|
|
171
|
+
|
|
172
|
+
mock_client.close.assert_awaited_once()
|
|
173
|
+
assert document_store._async_client is None
|
|
174
|
+
|
|
175
|
+
await document_store.close_async()
|
|
176
|
+
mock_client.close.assert_awaited_once()
|
|
177
|
+
|
|
178
|
+
async def test_close_async_is_exception_safe(self):
|
|
179
|
+
document_store = QdrantDocumentStore(location=":memory:")
|
|
180
|
+
mock_client = AsyncMock()
|
|
181
|
+
mock_client.close.side_effect = RuntimeError("boom")
|
|
182
|
+
document_store._async_client = mock_client
|
|
183
|
+
|
|
184
|
+
await document_store.close_async()
|
|
185
|
+
|
|
186
|
+
assert document_store._async_client is None
|
|
187
|
+
|
|
165
188
|
|
|
166
189
|
@pytest.mark.integration
|
|
167
190
|
@pytest.mark.asyncio
|
|
@@ -195,6 +218,16 @@ class TestQdrantDocumentStoreAsync(
|
|
|
195
218
|
assert len(received) == len(expected)
|
|
196
219
|
assert {doc.id for doc in received} == {doc.id for doc in expected}
|
|
197
220
|
|
|
221
|
+
async def test_close_async_and_reopen(self, document_store: QdrantDocumentStore):
|
|
222
|
+
assert await document_store.count_documents_async() == 0
|
|
223
|
+
assert document_store._async_client is not None
|
|
224
|
+
|
|
225
|
+
await document_store.close_async()
|
|
226
|
+
|
|
227
|
+
assert document_store._async_client is None
|
|
228
|
+
assert await document_store.count_documents_async() == 0
|
|
229
|
+
assert document_store._async_client is not None
|
|
230
|
+
|
|
198
231
|
@pytest.mark.asyncio
|
|
199
232
|
async def test_write_documents_async(self, document_store: QdrantDocumentStore):
|
|
200
233
|
docs = [Document(id="1")]
|
|
@@ -146,6 +146,26 @@ class TestQdrantRetriever:
|
|
|
146
146
|
retriever = QdrantEmbeddingRetriever.from_dict(data)
|
|
147
147
|
assert retriever._filter_policy == FilterPolicy.REPLACE # defaults to REPLACE
|
|
148
148
|
|
|
149
|
+
def test_close(self):
|
|
150
|
+
mock_store = Mock(spec=QdrantDocumentStore)
|
|
151
|
+
retriever = QdrantEmbeddingRetriever(document_store=mock_store)
|
|
152
|
+
|
|
153
|
+
retriever.close()
|
|
154
|
+
|
|
155
|
+
mock_store.close.assert_called_once_with()
|
|
156
|
+
assert retriever._document_store is mock_store
|
|
157
|
+
|
|
158
|
+
@pytest.mark.asyncio
|
|
159
|
+
async def test_close_async(self):
|
|
160
|
+
mock_store = Mock(spec=QdrantDocumentStore)
|
|
161
|
+
mock_store.close_async = AsyncMock()
|
|
162
|
+
retriever = QdrantEmbeddingRetriever(document_store=mock_store)
|
|
163
|
+
|
|
164
|
+
await retriever.close_async()
|
|
165
|
+
|
|
166
|
+
mock_store.close_async.assert_awaited_once_with()
|
|
167
|
+
assert retriever._document_store is mock_store
|
|
168
|
+
|
|
149
169
|
def test_run(self):
|
|
150
170
|
mock_store = Mock(spec=QdrantDocumentStore)
|
|
151
171
|
mock_store._query_by_embedding.return_value = [Document(content="doc", embedding=[0.1, 0.2])]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from unittest.mock import Mock
|
|
1
|
+
from unittest.mock import AsyncMock, Mock
|
|
2
2
|
|
|
3
3
|
import pytest
|
|
4
4
|
from haystack.dataclasses import Document, SparseEmbedding
|
|
@@ -146,6 +146,26 @@ class TestQdrantHybridRetriever:
|
|
|
146
146
|
assert retriever._group_by is None
|
|
147
147
|
assert retriever._group_size is None
|
|
148
148
|
|
|
149
|
+
def test_close(self):
|
|
150
|
+
mock_store = Mock(spec=QdrantDocumentStore)
|
|
151
|
+
retriever = QdrantHybridRetriever(document_store=mock_store)
|
|
152
|
+
|
|
153
|
+
retriever.close()
|
|
154
|
+
|
|
155
|
+
mock_store.close.assert_called_once_with()
|
|
156
|
+
assert retriever._document_store is mock_store
|
|
157
|
+
|
|
158
|
+
@pytest.mark.asyncio
|
|
159
|
+
async def test_close_async(self):
|
|
160
|
+
mock_store = Mock(spec=QdrantDocumentStore)
|
|
161
|
+
mock_store.close_async = AsyncMock()
|
|
162
|
+
retriever = QdrantHybridRetriever(document_store=mock_store)
|
|
163
|
+
|
|
164
|
+
await retriever.close_async()
|
|
165
|
+
|
|
166
|
+
mock_store.close_async.assert_awaited_once_with()
|
|
167
|
+
assert retriever._document_store is mock_store
|
|
168
|
+
|
|
149
169
|
def test_run(self):
|
|
150
170
|
mock_store = Mock(spec=QdrantDocumentStore)
|
|
151
171
|
sparse_embedding = SparseEmbedding(indices=[0, 1, 2, 3], values=[0.1, 0.8, 0.05, 0.33])
|
|
@@ -154,6 +154,26 @@ class TestQdrantSparseEmbeddingRetriever:
|
|
|
154
154
|
assert retriever._group_by is None
|
|
155
155
|
assert retriever._group_size is None
|
|
156
156
|
|
|
157
|
+
def test_close(self):
|
|
158
|
+
mock_store = Mock(spec=QdrantDocumentStore)
|
|
159
|
+
retriever = QdrantSparseEmbeddingRetriever(document_store=mock_store)
|
|
160
|
+
|
|
161
|
+
retriever.close()
|
|
162
|
+
|
|
163
|
+
mock_store.close.assert_called_once_with()
|
|
164
|
+
assert retriever._document_store is mock_store
|
|
165
|
+
|
|
166
|
+
@pytest.mark.asyncio
|
|
167
|
+
async def test_close_async(self):
|
|
168
|
+
mock_store = Mock(spec=QdrantDocumentStore)
|
|
169
|
+
mock_store.close_async = AsyncMock()
|
|
170
|
+
retriever = QdrantSparseEmbeddingRetriever(document_store=mock_store)
|
|
171
|
+
|
|
172
|
+
await retriever.close_async()
|
|
173
|
+
|
|
174
|
+
mock_store.close_async.assert_awaited_once_with()
|
|
175
|
+
assert retriever._document_store is mock_store
|
|
176
|
+
|
|
157
177
|
def test_run(self):
|
|
158
178
|
mock_store = Mock(spec=QdrantDocumentStore)
|
|
159
179
|
sparse = SparseEmbedding(indices=[0, 5], values=[0.1, 0.7])
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{qdrant_haystack-10.3.1 → qdrant_haystack-10.4.0}/src/haystack_integrations/document_stores/py.typed
RENAMED
|
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
|