pinecone-haystack 6.2.0__tar.gz → 6.3.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.
- {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/CHANGELOG.md +32 -0
- {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/PKG-INFO +1 -1
- {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/examples/example.py +4 -1
- {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/src/haystack_integrations/components/retrievers/pinecone/embedding_retriever.py +15 -2
- {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/src/haystack_integrations/document_stores/pinecone/document_store.py +9 -6
- {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/tests/test_document_store.py +30 -22
- {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/tests/test_document_store_async.py +48 -4
- {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/tests/test_embedding_retriever.py +23 -1
- {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/.gitignore +0 -0
- {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/README.md +0 -0
- {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/pydoc/config_docusaurus.yml +0 -0
- {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/pyproject.toml +0 -0
- {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/src/haystack_integrations/components/retrievers/pinecone/__init__.py +0 -0
- {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/src/haystack_integrations/components/retrievers/py.typed +0 -0
- {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/src/haystack_integrations/document_stores/pinecone/__init__.py +0 -0
- {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/src/haystack_integrations/document_stores/pinecone/filters.py +0 -0
- {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/src/haystack_integrations/document_stores/py.typed +0 -0
- {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/tests/__init__.py +0 -0
- {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/tests/conftest.py +0 -0
- {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/tests/test_filters.py +0 -0
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [integrations/pinecone-v6.2.0] - 2026-05-08
|
|
4
|
+
|
|
5
|
+
### 🐛 Bug Fixes
|
|
6
|
+
|
|
7
|
+
- Replace in-place dataclass mutations in document stores (#3114)
|
|
8
|
+
|
|
9
|
+
### 🚜 Refactor
|
|
10
|
+
|
|
11
|
+
- *(pinecone)* Make get_metadata_field_min_max more consistent; use async DocumentStore mixin tests (#3231)
|
|
12
|
+
|
|
13
|
+
### 📚 Documentation
|
|
14
|
+
|
|
15
|
+
- Simplify pydoc configs (#2855)
|
|
16
|
+
|
|
17
|
+
### 🧪 Testing
|
|
18
|
+
|
|
19
|
+
- Replacing each `DocumentStore` specific tests and used the generalised ones from `haystack.testing.document_store` (#2812)
|
|
20
|
+
- Test compatible integrations with python 3.14; update pyproject (#3001)
|
|
21
|
+
- `PineconeDocumentStore` use Mixin tests (#3020)
|
|
22
|
+
- Track test coverage for all integrations (#3065)
|
|
23
|
+
- Pinecone - add unit tests (#3218)
|
|
24
|
+
- Pinecone - remove namespaces when tests ends (#3248)
|
|
25
|
+
|
|
26
|
+
### 🧹 Chores
|
|
27
|
+
|
|
28
|
+
- Exposing `PineconeDocumentStore` `show_progress` bar parameter and disabling it for tests (#2799)
|
|
29
|
+
- Remove unused allow-direct-references (#2866)
|
|
30
|
+
- Add ANN ruff ruleset to optimum, paddleocr, pgvector, pinecone, pyversity, qdrant, ragas, snowflake (#2992)
|
|
31
|
+
- Enforce ruff docstring rules in integrations 31-40 (openrouter, opensearch, optimum, paddleocr, pgvector, pinecone, pyversity, qdrant, ragas, snowflake) (#3011)
|
|
32
|
+
- Pinecone - fix types for Pinecone 9 (#3277)
|
|
33
|
+
|
|
34
|
+
|
|
3
35
|
## [integrations/pinecone-v6.1.2] - 2026-01-28
|
|
4
36
|
|
|
5
37
|
### 🐛 Bug Fixes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pinecone_haystack
|
|
3
|
-
Version: 6.
|
|
3
|
+
Version: 6.3.0
|
|
4
4
|
Project-URL: Documentation, https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/pinecone#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/pinecone
|
|
@@ -12,11 +12,14 @@ import glob
|
|
|
12
12
|
|
|
13
13
|
from haystack import Pipeline
|
|
14
14
|
from haystack.components.converters import MarkdownToDocument
|
|
15
|
-
from haystack.components.embedders import SentenceTransformersDocumentEmbedder, SentenceTransformersTextEmbedder
|
|
16
15
|
from haystack.components.preprocessors import DocumentSplitter
|
|
17
16
|
from haystack.components.writers import DocumentWriter
|
|
18
17
|
from haystack.utils import Secret
|
|
19
18
|
|
|
19
|
+
from haystack_integrations.components.embedders.sentence_transformers import (
|
|
20
|
+
SentenceTransformersDocumentEmbedder,
|
|
21
|
+
SentenceTransformersTextEmbedder,
|
|
22
|
+
)
|
|
20
23
|
from haystack_integrations.components.retrievers.pinecone import PineconeEmbeddingRetriever
|
|
21
24
|
from haystack_integrations.document_stores.pinecone import PineconeDocumentStore
|
|
22
25
|
|
|
@@ -22,7 +22,9 @@ class PineconeEmbeddingRetriever:
|
|
|
22
22
|
from haystack.document_stores.types import DuplicatePolicy
|
|
23
23
|
from haystack import Document
|
|
24
24
|
from haystack import Pipeline
|
|
25
|
-
|
|
25
|
+
# Requires: pip install sentence-transformers-haystack
|
|
26
|
+
from haystack_integrations.components.embedders.sentence_transformers import SentenceTransformersTextEmbedder
|
|
27
|
+
from haystack_integrations.components.embedders.sentence_transformers import SentenceTransformersDocumentEmbedder
|
|
26
28
|
from haystack_integrations.components.retrievers.pinecone import PineconeEmbeddingRetriever
|
|
27
29
|
from haystack_integrations.document_stores.pinecone import PineconeDocumentStore
|
|
28
30
|
|
|
@@ -34,7 +36,6 @@ class PineconeEmbeddingRetriever:
|
|
|
34
36
|
Document(content="In certain places, you can witness the phenomenon of bioluminescent waves.")]
|
|
35
37
|
|
|
36
38
|
document_embedder = SentenceTransformersDocumentEmbedder()
|
|
37
|
-
document_embedder.warm_up()
|
|
38
39
|
documents_with_embeddings = document_embedder.run(documents)
|
|
39
40
|
|
|
40
41
|
document_store.write_documents(documents_with_embeddings.get("documents"), policy=DuplicatePolicy.OVERWRITE)
|
|
@@ -114,6 +115,18 @@ class PineconeEmbeddingRetriever:
|
|
|
114
115
|
data["init_parameters"]["filter_policy"] = FilterPolicy.from_str(filter_policy)
|
|
115
116
|
return default_from_dict(cls, data)
|
|
116
117
|
|
|
118
|
+
def close(self) -> None:
|
|
119
|
+
"""
|
|
120
|
+
Release the synchronous resources of the underlying Document Store.
|
|
121
|
+
"""
|
|
122
|
+
self.document_store.close()
|
|
123
|
+
|
|
124
|
+
async def close_async(self) -> None:
|
|
125
|
+
"""
|
|
126
|
+
Release the asynchronous resources of the underlying Document Store.
|
|
127
|
+
"""
|
|
128
|
+
await self.document_store.close_async()
|
|
129
|
+
|
|
117
130
|
@component.output_types(documents=list[Document])
|
|
118
131
|
def run(
|
|
119
132
|
self,
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
#
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
|
|
5
|
+
from contextlib import suppress
|
|
5
6
|
from copy import copy
|
|
6
7
|
from dataclasses import replace
|
|
7
8
|
from typing import Any, Literal
|
|
@@ -151,18 +152,20 @@ class PineconeDocumentStore:
|
|
|
151
152
|
|
|
152
153
|
def close(self) -> None:
|
|
153
154
|
"""
|
|
154
|
-
|
|
155
|
+
Release the associated synchronous resources.
|
|
155
156
|
"""
|
|
156
|
-
if self._index:
|
|
157
|
-
|
|
157
|
+
if self._index is not None:
|
|
158
|
+
with suppress(Exception):
|
|
159
|
+
self._index.close()
|
|
158
160
|
self._index = None
|
|
159
161
|
|
|
160
162
|
async def close_async(self) -> None:
|
|
161
163
|
"""
|
|
162
|
-
|
|
164
|
+
Release the associated asynchronous resources.
|
|
163
165
|
"""
|
|
164
|
-
if self._async_index:
|
|
165
|
-
|
|
166
|
+
if self._async_index is not None:
|
|
167
|
+
with suppress(Exception):
|
|
168
|
+
await self._async_index.close()
|
|
166
169
|
self._async_index = None
|
|
167
170
|
|
|
168
171
|
@staticmethod
|
|
@@ -4,7 +4,8 @@
|
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
6
|
import time
|
|
7
|
-
from
|
|
7
|
+
from dataclasses import replace
|
|
8
|
+
from unittest.mock import MagicMock, patch
|
|
8
9
|
|
|
9
10
|
import numpy as np
|
|
10
11
|
import pytest
|
|
@@ -127,7 +128,31 @@ def test_to_from_dict(mock_pinecone, monkeypatch):
|
|
|
127
128
|
assert document_store.dimension == 60
|
|
128
129
|
assert document_store.metric == "euclidean"
|
|
129
130
|
assert document_store.spec == {"serverless": {"region": "us-east-1", "cloud": "aws"}}
|
|
130
|
-
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def test_close():
|
|
134
|
+
document_store = PineconeDocumentStore(api_key=Secret.from_token("fake-api-key"))
|
|
135
|
+
mock_index = MagicMock()
|
|
136
|
+
document_store._index = mock_index
|
|
137
|
+
|
|
138
|
+
document_store.close()
|
|
139
|
+
|
|
140
|
+
mock_index.close.assert_called_once()
|
|
141
|
+
assert document_store._index is None
|
|
142
|
+
|
|
143
|
+
document_store.close()
|
|
144
|
+
mock_index.close.assert_called_once()
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def test_close_is_exception_safe():
|
|
148
|
+
document_store = PineconeDocumentStore(api_key=Secret.from_token("fake-api-key"))
|
|
149
|
+
mock_index = MagicMock()
|
|
150
|
+
mock_index.close.side_effect = RuntimeError("boom")
|
|
151
|
+
document_store._index = mock_index
|
|
152
|
+
|
|
153
|
+
document_store.close()
|
|
154
|
+
|
|
155
|
+
assert document_store._index is None
|
|
131
156
|
|
|
132
157
|
|
|
133
158
|
def test_init_fails_wo_api_key(monkeypatch):
|
|
@@ -340,22 +365,6 @@ def test_prepare_documents_for_writing_edge_cases(caplog):
|
|
|
340
365
|
assert "sparse_embedding" in caplog.text
|
|
341
366
|
|
|
342
367
|
|
|
343
|
-
@pytest.mark.asyncio
|
|
344
|
-
async def test_validation_errors_on_empty_query_and_non_dict_meta():
|
|
345
|
-
ds = PineconeDocumentStore(api_key=Secret.from_token("fake-api-key"))
|
|
346
|
-
filters = {"field": "meta.category", "operator": "==", "value": "A"}
|
|
347
|
-
|
|
348
|
-
with pytest.raises(ValueError, match="query_embedding must be a non-empty list"):
|
|
349
|
-
ds._embedding_retrieval(query_embedding=[])
|
|
350
|
-
with pytest.raises(ValueError, match="query_embedding must be a non-empty list"):
|
|
351
|
-
await ds._embedding_retrieval_async(query_embedding=[])
|
|
352
|
-
|
|
353
|
-
with pytest.raises(ValueError, match="meta must be a dictionary"):
|
|
354
|
-
ds.update_by_filter(filters=filters, meta="not-a-dict")
|
|
355
|
-
with pytest.raises(ValueError, match="meta must be a dictionary"):
|
|
356
|
-
await ds.update_by_filter_async(filters=filters, meta="not-a-dict")
|
|
357
|
-
|
|
358
|
-
|
|
359
368
|
@pytest.mark.integration
|
|
360
369
|
@pytest.mark.skipif(not os.environ.get("PINECONE_API_KEY"), reason="PINECONE_API_KEY not set")
|
|
361
370
|
def test_serverless_index_creation_from_scratch(delete_sleep_time):
|
|
@@ -452,7 +461,7 @@ class TestDocumentStore(
|
|
|
452
461
|
assert "Most similar document" in [result.content for result in results]
|
|
453
462
|
assert "2nd best document" in [result.content for result in results]
|
|
454
463
|
|
|
455
|
-
def
|
|
464
|
+
def test_close_and_reopen(self, document_store: PineconeDocumentStore):
|
|
456
465
|
document_store._initialize_index()
|
|
457
466
|
assert document_store._index is not None
|
|
458
467
|
|
|
@@ -461,7 +470,6 @@ class TestDocumentStore(
|
|
|
461
470
|
|
|
462
471
|
document_store._initialize_index()
|
|
463
472
|
assert document_store._index is not None
|
|
464
|
-
# test that the index is still usable after closing and reopening
|
|
465
473
|
assert document_store.count_documents() == 0
|
|
466
474
|
|
|
467
475
|
def test_sentence_window_retriever(self, document_store: PineconeDocumentStore):
|
|
@@ -475,9 +483,9 @@ class TestDocumentStore(
|
|
|
475
483
|
|
|
476
484
|
for idx, doc in enumerate(docs["documents"]):
|
|
477
485
|
if idx == 2:
|
|
478
|
-
doc
|
|
486
|
+
docs["documents"][idx] = replace(doc, embedding=[0.1] * 768)
|
|
479
487
|
continue
|
|
480
|
-
doc
|
|
488
|
+
docs["documents"][idx] = replace(doc, embedding=np.random.rand(768).tolist())
|
|
481
489
|
document_store.write_documents(docs["documents"])
|
|
482
490
|
|
|
483
491
|
# query
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import os
|
|
6
6
|
from dataclasses import replace
|
|
7
|
+
from unittest.mock import AsyncMock
|
|
7
8
|
|
|
8
9
|
import numpy as np
|
|
9
10
|
import pytest
|
|
@@ -25,11 +26,55 @@ from haystack.testing.document_store_async import (
|
|
|
25
26
|
UpdateByFilterAsyncTest,
|
|
26
27
|
WriteDocumentsAsyncTest,
|
|
27
28
|
)
|
|
29
|
+
from haystack.utils import Secret
|
|
28
30
|
|
|
29
31
|
from haystack_integrations.components.retrievers.pinecone import PineconeEmbeddingRetriever
|
|
30
32
|
from haystack_integrations.document_stores.pinecone import PineconeDocumentStore
|
|
31
33
|
|
|
32
34
|
|
|
35
|
+
@pytest.mark.asyncio
|
|
36
|
+
async def test_close_async():
|
|
37
|
+
document_store = PineconeDocumentStore(api_key=Secret.from_token("fake-api-key"))
|
|
38
|
+
mock_index = AsyncMock()
|
|
39
|
+
document_store._async_index = mock_index
|
|
40
|
+
|
|
41
|
+
await document_store.close_async()
|
|
42
|
+
|
|
43
|
+
mock_index.close.assert_awaited_once()
|
|
44
|
+
assert document_store._async_index is None
|
|
45
|
+
|
|
46
|
+
await document_store.close_async()
|
|
47
|
+
mock_index.close.assert_awaited_once()
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
@pytest.mark.asyncio
|
|
51
|
+
async def test_close_async_is_exception_safe():
|
|
52
|
+
document_store = PineconeDocumentStore(api_key=Secret.from_token("fake-api-key"))
|
|
53
|
+
mock_index = AsyncMock()
|
|
54
|
+
mock_index.close.side_effect = RuntimeError("boom")
|
|
55
|
+
document_store._async_index = mock_index
|
|
56
|
+
|
|
57
|
+
await document_store.close_async()
|
|
58
|
+
|
|
59
|
+
assert document_store._async_index is None
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@pytest.mark.asyncio
|
|
63
|
+
async def test_validation_errors_on_empty_query_and_non_dict_meta():
|
|
64
|
+
ds = PineconeDocumentStore(api_key=Secret.from_token("fake-api-key"))
|
|
65
|
+
filters = {"field": "meta.category", "operator": "==", "value": "A"}
|
|
66
|
+
|
|
67
|
+
with pytest.raises(ValueError, match="query_embedding must be a non-empty list"):
|
|
68
|
+
ds._embedding_retrieval(query_embedding=[])
|
|
69
|
+
with pytest.raises(ValueError, match="query_embedding must be a non-empty list"):
|
|
70
|
+
await ds._embedding_retrieval_async(query_embedding=[])
|
|
71
|
+
|
|
72
|
+
with pytest.raises(ValueError, match="meta must be a dictionary"):
|
|
73
|
+
ds.update_by_filter(filters=filters, meta="not-a-dict")
|
|
74
|
+
with pytest.raises(ValueError, match="meta must be a dictionary"):
|
|
75
|
+
await ds.update_by_filter_async(filters=filters, meta="not-a-dict")
|
|
76
|
+
|
|
77
|
+
|
|
33
78
|
@pytest.mark.integration
|
|
34
79
|
@pytest.mark.asyncio
|
|
35
80
|
@pytest.mark.skipif(not os.environ.get("PINECONE_API_KEY"), reason="PINECONE_API_KEY not set")
|
|
@@ -114,7 +159,7 @@ class TestDocumentStoreAsync(
|
|
|
114
159
|
assert "Most similar document" in [result.content for result in results]
|
|
115
160
|
assert "2nd best document" in [result.content for result in results]
|
|
116
161
|
|
|
117
|
-
async def
|
|
162
|
+
async def test_close_async_and_reopen(self, document_store_async: PineconeDocumentStore):
|
|
118
163
|
await document_store_async._initialize_async_index()
|
|
119
164
|
assert document_store_async._async_index is not None
|
|
120
165
|
|
|
@@ -123,7 +168,6 @@ class TestDocumentStoreAsync(
|
|
|
123
168
|
|
|
124
169
|
await document_store_async._initialize_async_index()
|
|
125
170
|
assert document_store_async._async_index is not None
|
|
126
|
-
# test that the index is still usable after closing and reopening
|
|
127
171
|
assert await document_store_async.count_documents_async() == 0
|
|
128
172
|
|
|
129
173
|
async def test_sentence_window_retriever(self, document_store_async: PineconeDocumentStore):
|
|
@@ -137,9 +181,9 @@ class TestDocumentStoreAsync(
|
|
|
137
181
|
|
|
138
182
|
for idx, doc in enumerate(docs["documents"]):
|
|
139
183
|
if idx == 2:
|
|
140
|
-
doc
|
|
184
|
+
docs["documents"][idx] = replace(doc, embedding=[0.1] * 768)
|
|
141
185
|
continue
|
|
142
|
-
doc
|
|
186
|
+
docs["documents"][idx] = replace(doc, embedding=np.random.rand(768).tolist())
|
|
143
187
|
await document_store_async.write_documents_async(docs["documents"])
|
|
144
188
|
|
|
145
189
|
# query
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
#
|
|
3
3
|
# SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
|
|
5
|
-
from unittest.mock import Mock, patch
|
|
5
|
+
from unittest.mock import AsyncMock, Mock, patch
|
|
6
6
|
|
|
7
7
|
import pytest
|
|
8
8
|
from haystack.dataclasses import Document
|
|
@@ -33,6 +33,28 @@ def test_init_raises_for_non_pinecone_document_store():
|
|
|
33
33
|
PineconeEmbeddingRetriever(document_store="not-a-document-store")
|
|
34
34
|
|
|
35
35
|
|
|
36
|
+
def test_close():
|
|
37
|
+
mock_store = Mock(spec=PineconeDocumentStore)
|
|
38
|
+
retriever = PineconeEmbeddingRetriever(document_store=mock_store)
|
|
39
|
+
|
|
40
|
+
retriever.close()
|
|
41
|
+
|
|
42
|
+
mock_store.close.assert_called_once_with()
|
|
43
|
+
assert retriever.document_store is mock_store
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
@pytest.mark.asyncio
|
|
47
|
+
async def test_close_async():
|
|
48
|
+
mock_store = Mock(spec=PineconeDocumentStore)
|
|
49
|
+
mock_store.close_async = AsyncMock()
|
|
50
|
+
retriever = PineconeEmbeddingRetriever(document_store=mock_store)
|
|
51
|
+
|
|
52
|
+
await retriever.close_async()
|
|
53
|
+
|
|
54
|
+
mock_store.close_async.assert_awaited_once_with()
|
|
55
|
+
assert retriever.document_store is mock_store
|
|
56
|
+
|
|
57
|
+
|
|
36
58
|
@patch("haystack_integrations.document_stores.pinecone.document_store.Pinecone")
|
|
37
59
|
def test_to_dict(mock_pinecone, monkeypatch):
|
|
38
60
|
monkeypatch.setenv("PINECONE_API_KEY", "env-api-key")
|
|
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
|