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.
Files changed (20) hide show
  1. {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/CHANGELOG.md +32 -0
  2. {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/PKG-INFO +1 -1
  3. {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/examples/example.py +4 -1
  4. {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/src/haystack_integrations/components/retrievers/pinecone/embedding_retriever.py +15 -2
  5. {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/src/haystack_integrations/document_stores/pinecone/document_store.py +9 -6
  6. {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/tests/test_document_store.py +30 -22
  7. {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/tests/test_document_store_async.py +48 -4
  8. {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/tests/test_embedding_retriever.py +23 -1
  9. {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/.gitignore +0 -0
  10. {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/README.md +0 -0
  11. {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/pydoc/config_docusaurus.yml +0 -0
  12. {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/pyproject.toml +0 -0
  13. {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/src/haystack_integrations/components/retrievers/pinecone/__init__.py +0 -0
  14. {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/src/haystack_integrations/components/retrievers/py.typed +0 -0
  15. {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/src/haystack_integrations/document_stores/pinecone/__init__.py +0 -0
  16. {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/src/haystack_integrations/document_stores/pinecone/filters.py +0 -0
  17. {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/src/haystack_integrations/document_stores/py.typed +0 -0
  18. {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/tests/__init__.py +0 -0
  19. {pinecone_haystack-6.2.0 → pinecone_haystack-6.3.0}/tests/conftest.py +0 -0
  20. {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.2.0
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
- from haystack.components.embedders import SentenceTransformersTextEmbedder, SentenceTransformersDocumentEmbedder
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
- Close the associated synchronous resources.
155
+ Release the associated synchronous resources.
155
156
  """
156
- if self._index:
157
- self._index.close()
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
- Close the associated asynchronous resources. To be invoked manually when the Document Store is no longer needed.
164
+ Release the associated asynchronous resources.
163
165
  """
164
- if self._async_index:
165
- await self._async_index.close()
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 unittest.mock import patch
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
- assert document_store.show_progress is True
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 test_close(self, document_store: PineconeDocumentStore):
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.embedding = [0.1] * 768
486
+ docs["documents"][idx] = replace(doc, embedding=[0.1] * 768)
479
487
  continue
480
- doc.embedding = np.random.rand(768).tolist()
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 test_close(self, document_store_async: PineconeDocumentStore):
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.embedding = [0.1] * 768
184
+ docs["documents"][idx] = replace(doc, embedding=[0.1] * 768)
141
185
  continue
142
- doc.embedding = np.random.rand(768).tolist()
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")