pgvector-haystack 7.0.0__tar.gz → 8.1.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 (27) hide show
  1. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/CHANGELOG.md +19 -0
  2. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/PKG-INFO +3 -3
  3. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/pyproject.toml +2 -2
  4. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/src/haystack_integrations/document_stores/pgvector/document_store.py +44 -22
  5. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/tests/test_document_store.py +21 -0
  6. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/tests/test_document_store_async.py +27 -0
  7. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/.gitignore +0 -0
  8. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/LICENSE.txt +0 -0
  9. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/README.md +0 -0
  10. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/examples/embedding_retrieval.py +0 -0
  11. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/examples/hybrid_retrieval.py +0 -0
  12. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/pydoc/config_docusaurus.yml +0 -0
  13. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/src/haystack_integrations/components/retrievers/pgvector/__init__.py +0 -0
  14. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/src/haystack_integrations/components/retrievers/pgvector/embedding_retriever.py +0 -0
  15. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/src/haystack_integrations/components/retrievers/pgvector/keyword_retriever.py +0 -0
  16. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/src/haystack_integrations/components/retrievers/py.typed +0 -0
  17. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/src/haystack_integrations/document_stores/pgvector/__init__.py +0 -0
  18. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/src/haystack_integrations/document_stores/pgvector/converters.py +0 -0
  19. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/src/haystack_integrations/document_stores/pgvector/filters.py +0 -0
  20. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/src/haystack_integrations/document_stores/py.typed +0 -0
  21. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/tests/__init__.py +0 -0
  22. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/tests/conftest.py +0 -0
  23. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/tests/test_converters.py +0 -0
  24. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/tests/test_filters.py +0 -0
  25. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/tests/test_retrieval.py +0 -0
  26. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/tests/test_retrieval_async.py +0 -0
  27. {pgvector_haystack-7.0.0 → pgvector_haystack-8.1.0}/tests/test_retrievers.py +0 -0
@@ -1,5 +1,24 @@
1
1
  # Changelog
2
2
 
3
+ ## [integrations/pgvector-v8.0.0] - 2026-10-16
4
+
5
+ ### 🧪 Testing
6
+
7
+ - Test compatible integrations with Python 3.15; update pyproject (#4104)
8
+
9
+ ### 🧹 Chores
10
+
11
+ - Drop redundant deserialize_secrets_inplace calls in integrations requiring haystack-ai>=2.23 (#4058)
12
+ - [**breaking**] Drop Python 3.10 support (#4105)
13
+
14
+
15
+ ## [integrations/pgvector-v7.0.0] - 2026-09-29
16
+
17
+ ### 🐛 Bug Fixes
18
+
19
+ - [**breaking**] Pgvector - an empty filter must not delete every document (#4006)
20
+
21
+
3
22
  ## [integrations/pgvector-v6.6.1] - 2026-09-25
4
23
 
5
24
  ### 🐛 Bug Fixes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: pgvector-haystack
3
- Version: 7.0.0
3
+ Version: 8.1.0
4
4
  Summary: An integration of pgvector (vector search extension for Postgres) 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/pgvector/README.md
@@ -11,14 +11,14 @@ License-File: LICENSE.txt
11
11
  Classifier: Development Status :: 4 - Beta
12
12
  Classifier: License :: OSI Approved :: Apache Software License
13
13
  Classifier: Programming Language :: Python
14
- Classifier: Programming Language :: Python :: 3.10
15
14
  Classifier: Programming Language :: Python :: 3.11
16
15
  Classifier: Programming Language :: Python :: 3.12
17
16
  Classifier: Programming Language :: Python :: 3.13
18
17
  Classifier: Programming Language :: Python :: 3.14
18
+ Classifier: Programming Language :: Python :: 3.15
19
19
  Classifier: Programming Language :: Python :: Implementation :: CPython
20
20
  Classifier: Programming Language :: Python :: Implementation :: PyPy
21
- Requires-Python: >=3.10
21
+ Requires-Python: >=3.11
22
22
  Requires-Dist: haystack-ai>=2.28.0
23
23
  Requires-Dist: pgvector>=0.3.0
24
24
  Requires-Dist: psycopg[binary]
@@ -7,7 +7,7 @@ name = "pgvector-haystack"
7
7
  dynamic = ["version"]
8
8
  description = "An integration of pgvector (vector search extension for Postgres) with Haystack"
9
9
  readme = "README.md"
10
- requires-python = ">=3.10"
10
+ requires-python = ">=3.11"
11
11
  license = "Apache-2.0"
12
12
  keywords = []
13
13
  authors = [{ name = "deepset GmbH", email = "info@deepset.ai" }]
@@ -15,11 +15,11 @@ 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.10",
19
18
  "Programming Language :: Python :: 3.11",
20
19
  "Programming Language :: Python :: 3.12",
21
20
  "Programming Language :: Python :: 3.13",
22
21
  "Programming Language :: Python :: 3.14",
22
+ "Programming Language :: Python :: 3.15",
23
23
  "Programming Language :: Python :: Implementation :: CPython",
24
24
  "Programming Language :: Python :: Implementation :: PyPy",
25
25
  ]
@@ -10,7 +10,7 @@ from haystack.dataclasses.document import Document
10
10
  from haystack.document_stores.errors import DocumentStoreError, DuplicateDocumentError
11
11
  from haystack.document_stores.types import DuplicatePolicy
12
12
  from haystack.errors import FilterError
13
- from haystack.utils.auth import Secret, deserialize_secrets_inplace
13
+ from haystack.utils.auth import Secret
14
14
  from psycopg import AsyncConnection, Connection, Cursor, Error, IntegrityError
15
15
  from psycopg.cursor_async import AsyncCursor
16
16
  from psycopg.rows import DictRow, dict_row
@@ -222,7 +222,6 @@ class PgvectorDocumentStore:
222
222
  :returns:
223
223
  Deserialized component.
224
224
  """
225
- deserialize_secrets_inplace(data["init_parameters"], ["connection_string"])
226
225
  return default_from_dict(cls, data)
227
226
 
228
227
  def close(self) -> None:
@@ -371,6 +370,47 @@ class PgvectorDocumentStore:
371
370
 
372
371
  return result
373
372
 
373
+ def _create_connection(self) -> Connection:
374
+ """
375
+ Opens a new connection to the PostgreSQL database.
376
+
377
+ Subclasses can override this method to connect differently (e.g. through a cloud provider's connector).
378
+ It must only open and return the connection: autocommit, the pgvector extension, vector type
379
+ registration, cursors, and table initialization are handled by `_ensure_db_setup`.
380
+
381
+ :raises DocumentStoreError: If the connection cannot be opened.
382
+ """
383
+ conn_str = self.connection_string.resolve_value() or ""
384
+ try:
385
+ return Connection.connect(conn_str)
386
+ except Error as e:
387
+ msg = (
388
+ "Failed to connect to PostgreSQL database. Ensure the connection string follows the "
389
+ "PostgreSQL connection specification: "
390
+ "https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING."
391
+ )
392
+ raise DocumentStoreError(msg) from e
393
+
394
+ async def _create_connection_async(self) -> AsyncConnection:
395
+ """
396
+ Opens a new async connection to the PostgreSQL database.
397
+
398
+ Async counterpart of `_create_connection`, overridable in the same way. Everything else is handled by
399
+ `_ensure_db_setup_async`.
400
+
401
+ :raises DocumentStoreError: If the connection cannot be opened.
402
+ """
403
+ conn_str = self.connection_string.resolve_value() or ""
404
+ try:
405
+ return await AsyncConnection.connect(conn_str)
406
+ except Error as e:
407
+ msg = (
408
+ "Failed to connect to PostgreSQL database. Ensure the connection string follows the "
409
+ "PostgreSQL connection specification: "
410
+ "https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING."
411
+ )
412
+ raise DocumentStoreError(msg) from e
413
+
374
414
  def _ensure_db_setup(self) -> None:
375
415
  """
376
416
  Ensures that the connection to the PostgreSQL database exists and is valid.
@@ -388,16 +428,7 @@ class PgvectorDocumentStore:
388
428
  except Error as e:
389
429
  logger.debug("Failed to close connection: {e}", e=str(e))
390
430
 
391
- conn_str = self.connection_string.resolve_value() or ""
392
- try:
393
- connection = Connection.connect(conn_str)
394
- except Error as e:
395
- msg = (
396
- "Failed to connect to PostgreSQL database. Ensure the connection string follows the "
397
- "PostgreSQL connection specification: "
398
- "https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING."
399
- )
400
- raise DocumentStoreError(msg) from e
431
+ connection = self._create_connection()
401
432
  connection.autocommit = True
402
433
  if self.create_extension:
403
434
  connection.execute("CREATE EXTENSION IF NOT EXISTS vector")
@@ -431,16 +462,7 @@ class PgvectorDocumentStore:
431
462
  if self._async_connection:
432
463
  await self._async_connection.close()
433
464
 
434
- conn_str = self.connection_string.resolve_value() or ""
435
- try:
436
- async_connection = await AsyncConnection.connect(conn_str)
437
- except Error as e:
438
- msg = (
439
- "Failed to connect to PostgreSQL database. Ensure the connection string follows the "
440
- "PostgreSQL connection specification: "
441
- "https://www.postgresql.org/docs/current/libpq-connect.html#LIBPQ-CONNSTRING."
442
- )
443
- raise DocumentStoreError(msg) from e
465
+ async_connection = await self._create_connection_async()
444
466
  await async_connection.set_autocommit(True)
445
467
  if self.create_extension:
446
468
  await async_connection.execute("CREATE EXTENSION IF NOT EXISTS vector")
@@ -448,6 +448,27 @@ def test_close_is_exception_safe(mock_store):
448
448
  assert mock_store._connection is None
449
449
 
450
450
 
451
+ @pytest.mark.usefixtures("patches_for_unit_tests")
452
+ def test_ensure_db_setup_uses_overridden_create_connection(monkeypatch):
453
+ monkeypatch.setenv("PG_CONN_STR", "some-connection-string")
454
+ mock_connection = Mock(spec=Connection)
455
+
456
+ class CustomConnectionDocumentStore(PgvectorDocumentStore):
457
+ def _create_connection(self) -> Connection:
458
+ return mock_connection
459
+
460
+ store = CustomConnectionDocumentStore()
461
+ with patch.object(CustomConnectionDocumentStore, "_initialize_table") as mock_initialize_table:
462
+ store._ensure_db_setup()
463
+
464
+ assert store._connection is mock_connection
465
+ assert mock_connection.autocommit is True
466
+ mock_connection.execute.assert_called_once_with("CREATE EXTENSION IF NOT EXISTS vector")
467
+ assert store._cursor is not None
468
+ assert store._dict_cursor is not None
469
+ mock_initialize_table.assert_called_once()
470
+
471
+
451
472
  @pytest.mark.integration
452
473
  def test_halfvec_hnsw_write_documents(document_store_w_halfvec_hnsw_index: PgvectorDocumentStore):
453
474
  documents = [
@@ -409,3 +409,30 @@ async def test_close_async_is_exception_safe(mock_store):
409
409
  await mock_store.close_async()
410
410
 
411
411
  assert mock_store._async_connection is None
412
+
413
+
414
+ @pytest.mark.asyncio
415
+ async def test_ensure_db_setup_async_uses_overridden_create_connection_async(monkeypatch):
416
+ monkeypatch.setenv("PG_CONN_STR", "some-connection-string")
417
+ mock_connection = Mock(spec=AsyncConnection)
418
+ mock_connection.set_autocommit = AsyncMock()
419
+ mock_connection.execute = AsyncMock()
420
+
421
+ class CustomConnectionDocumentStore(PgvectorDocumentStore):
422
+ async def _create_connection_async(self) -> AsyncConnection:
423
+ return mock_connection
424
+
425
+ store = CustomConnectionDocumentStore()
426
+ with (
427
+ patch("haystack_integrations.document_stores.pgvector.document_store.register_vector_async") as mock_register,
428
+ patch.object(CustomConnectionDocumentStore, "_initialize_table_async") as mock_initialize_table,
429
+ ):
430
+ await store._ensure_db_setup_async()
431
+
432
+ assert store._async_connection is mock_connection
433
+ mock_connection.set_autocommit.assert_awaited_once_with(True)
434
+ mock_connection.execute.assert_awaited_once_with("CREATE EXTENSION IF NOT EXISTS vector")
435
+ mock_register.assert_awaited_once_with(mock_connection)
436
+ assert store._async_cursor is not None
437
+ assert store._async_dict_cursor is not None
438
+ mock_initialize_table.assert_awaited_once()