pgvector-template 0.3.3__tar.gz → 0.3.5__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_template-0.3.3 → pgvector_template-0.3.5}/PKG-INFO +3 -2
  2. {pgvector_template-0.3.3 → pgvector_template-0.3.5}/pgvector_template/__init__.py +1 -1
  3. {pgvector_template-0.3.3 → pgvector_template-0.3.5}/pgvector_template/core/__init__.py +5 -1
  4. {pgvector_template-0.3.3 → pgvector_template-0.3.5}/pgvector_template/core/document.py +1 -1
  5. {pgvector_template-0.3.3 → pgvector_template-0.3.5}/pgvector_template/core/manager.py +20 -9
  6. {pgvector_template-0.3.3 → pgvector_template-0.3.5}/pgvector_template/db/connection.py +16 -6
  7. {pgvector_template-0.3.3 → pgvector_template-0.3.5}/pgvector_template/db/document_db.py +4 -2
  8. pgvector_template-0.3.5/pgvector_template/models/__init__.py +5 -0
  9. {pgvector_template-0.3.3 → pgvector_template-0.3.5}/pgvector_template/models/search.py +1 -1
  10. {pgvector_template-0.3.3 → pgvector_template-0.3.5}/pgvector_template/service/document_service.py +1 -2
  11. {pgvector_template-0.3.3 → pgvector_template-0.3.5}/pgvector_template/utils/metadata_filter.py +3 -3
  12. {pgvector_template-0.3.3 → pgvector_template-0.3.5}/pgvector_template.egg-info/PKG-INFO +3 -2
  13. {pgvector_template-0.3.3 → pgvector_template-0.3.5}/pgvector_template.egg-info/requires.txt +2 -1
  14. {pgvector_template-0.3.3 → pgvector_template-0.3.5}/pyproject.toml +8 -4
  15. pgvector_template-0.3.3/pgvector_template/models/__init__.py +0 -1
  16. {pgvector_template-0.3.3 → pgvector_template-0.3.5}/LICENSE +0 -0
  17. {pgvector_template-0.3.3 → pgvector_template-0.3.5}/README.md +0 -0
  18. {pgvector_template-0.3.3 → pgvector_template-0.3.5}/pgvector_template/core/embedder.py +0 -0
  19. {pgvector_template-0.3.3 → pgvector_template-0.3.5}/pgvector_template/core/search.py +0 -0
  20. {pgvector_template-0.3.3 → pgvector_template-0.3.5}/pgvector_template/db/__init__.py +0 -0
  21. {pgvector_template-0.3.3 → pgvector_template-0.3.5}/pgvector_template/service/__init__.py +0 -0
  22. {pgvector_template-0.3.3 → pgvector_template-0.3.5}/pgvector_template/types.py +0 -0
  23. {pgvector_template-0.3.3 → pgvector_template-0.3.5}/pgvector_template/utils/__init__.py +0 -0
  24. {pgvector_template-0.3.3 → pgvector_template-0.3.5}/pgvector_template.egg-info/SOURCES.txt +0 -0
  25. {pgvector_template-0.3.3 → pgvector_template-0.3.5}/pgvector_template.egg-info/dependency_links.txt +0 -0
  26. {pgvector_template-0.3.3 → pgvector_template-0.3.5}/pgvector_template.egg-info/top_level.txt +0 -0
  27. {pgvector_template-0.3.3 → pgvector_template-0.3.5}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pgvector-template
3
- Version: 0.3.3
3
+ Version: 0.3.5
4
4
  Summary: Template library for flexible PGVector RAG implementations
5
5
  Author-email: DL <v49t9zpqd@mozmail.com>
6
6
  License: MIT
@@ -21,7 +21,8 @@ Requires-Dist: pytest>=7.0.0; extra == "test"
21
21
  Requires-Dist: pytest-cov>=4.0.0; extra == "test"
22
22
  Requires-Dist: python-dotenv>=1.0.0; extra == "test"
23
23
  Provides-Extra: dev
24
- Requires-Dist: black>=23.0.0; extra == "dev"
24
+ Requires-Dist: ruff>=0.9.0; extra == "dev"
25
+ Requires-Dist: ty>=0.0.1a0; extra == "dev"
25
26
  Provides-Extra: dist
26
27
  Requires-Dist: build>=1.2.2; extra == "dist"
27
28
  Requires-Dist: twine>=6.1.0; extra == "dist"
@@ -3,4 +3,4 @@ from pgvector_template.db.connection import DatabaseManager
3
3
  from pgvector_template.db.document_db import DocumentDatabaseManager
4
4
 
5
5
  # Re-export at the top level
6
- __all__ = ["DatabaseManager", "DocumentDatabaseManager"]
6
+ __all__ = ["DatabaseManager", "DocumentDatabaseManager"]
@@ -1,4 +1,8 @@
1
- from pgvector_template.core.document import BaseDocument, BaseDocumentMetadata, BaseDocumentOptionalProps
1
+ from pgvector_template.core.document import (
2
+ BaseDocument,
3
+ BaseDocumentMetadata,
4
+ BaseDocumentOptionalProps,
5
+ )
2
6
  from pgvector_template.core.embedder import BaseEmbeddingProvider
3
7
  from pgvector_template.core.manager import BaseCorpusManager, BaseCorpusManagerConfig, Corpus
4
8
  from pgvector_template.core.search import BaseSearchClientConfig, BaseSearchClient
@@ -2,7 +2,7 @@ from datetime import datetime
2
2
  from typing import Any, Type, TypeVar
3
3
  from uuid import uuid4, UUID as UuidLiteral
4
4
 
5
- from pydantic import BaseModel, Field, field_validator, model_validator
5
+ from pydantic import BaseModel, Field, field_validator
6
6
  from sqlalchemy import (
7
7
  Column,
8
8
  String,
@@ -1,7 +1,7 @@
1
- from abc import ABC, abstractmethod
1
+ from abc import ABC
2
2
  from dataclasses import dataclass
3
3
  from logging import getLogger
4
- from typing import Any, Literal, Type
4
+ from typing import Any, Type
5
5
  from uuid import UUID, uuid4
6
6
 
7
7
  from pydantic import BaseModel, Field
@@ -88,7 +88,7 @@ class BaseCorpusManager(ABC):
88
88
  self.session.query(self.config.document_cls)
89
89
  .filter(
90
90
  self.config.document_cls.corpus_id == corpus_id,
91
- self.config.document_cls.is_deleted == False,
91
+ self.config.document_cls.is_deleted == False, # noqa: E712
92
92
  )
93
93
  .order_by(self.config.document_cls.chunk_index)
94
94
  .all()
@@ -105,6 +105,15 @@ class BaseCorpusManager(ABC):
105
105
  documents=chunks,
106
106
  )
107
107
 
108
+ def _generate_corpus_id(
109
+ self, corpus_id: UUID | str | None = None, content: str | None = None
110
+ ) -> UUID | str:
111
+ """
112
+ Helper to generate a corpus_id if not provided.
113
+ Override this method to provide a consistent way to generate.
114
+ """
115
+ return corpus_id if corpus_id else uuid4()
116
+
108
117
  def insert_corpus(
109
118
  self,
110
119
  content: str,
@@ -126,8 +135,7 @@ class BaseCorpusManager(ABC):
126
135
  Returns:
127
136
  int: The number of **documents** inserted for the provided corpus
128
137
  """
129
- if not corpus_id:
130
- corpus_id = uuid4()
138
+ corpus_id = self._generate_corpus_id(corpus_id)
131
139
  document_contents = self._split_corpus(content)
132
140
  document_embeddings = self.embedding_provider.embed_batch(document_contents)
133
141
  return self.insert_documents(
@@ -214,9 +222,12 @@ class BaseCorpusManager(ABC):
214
222
 
215
223
  def _delete_existing_corpus(self, corpus_id: UUID | str) -> None:
216
224
  """Delete all existing documents for the given corpus_id"""
217
- self.session.query(self.config.document_cls).filter(
225
+ query = self.session.query(self.config.document_cls).filter(
218
226
  self.config.document_cls.corpus_id == corpus_id
219
- ).delete()
227
+ )
228
+ if count := query.count():
229
+ logger.warning(f"Deleting {count} existing documents for corpus_id: {corpus_id}")
230
+ query.delete()
220
231
 
221
232
  def _split_corpus(self, content: str, **kwargs) -> list[str]:
222
233
  """
@@ -244,9 +255,9 @@ class BaseCorpusManager(ABC):
244
255
  logger.warning(
245
256
  "Using default _join_documents. Override this method to improve functionality."
246
257
  )
247
- documents.sort(key=lambda d: d.chunk_index) # type: ignore
258
+ documents.sort(key=lambda d: d.chunk_index)
248
259
  # since _split_corpus performs a simple split on every 1000 chars, we can simply call `join`
249
- corpus_content = "".join(d.content for d in documents) # type: ignore
260
+ corpus_content = "".join(d.content for d in documents) # ty: ignore[no-matching-overload]
250
261
  corpus_metadata = self._infer_corpus_metadata(documents)
251
262
  return corpus_content, corpus_metadata
252
263
 
@@ -2,7 +2,7 @@ from contextlib import contextmanager
2
2
  from logging import getLogger
3
3
  from typing import Generator, Type
4
4
 
5
- from sqlalchemy import create_engine, text
5
+ from sqlalchemy import Engine, create_engine, text
6
6
  from sqlalchemy.orm import sessionmaker, Session
7
7
  from sqlalchemy.ext.declarative import DeclarativeMeta
8
8
 
@@ -12,21 +12,29 @@ class DatabaseManager:
12
12
 
13
13
  def __init__(self, database_url: str):
14
14
  self.database_url = database_url
15
- self.engine = None
15
+ self.engine: Engine | None = None
16
16
  self.SessionLocal = None
17
17
  self.logger = getLogger(self.__class__.__name__)
18
18
 
19
+ def _require_engine(self) -> Engine:
20
+ if self.engine is None:
21
+ raise RuntimeError("DatabaseManager not initialized. Call initialize() first.")
22
+ return self.engine
23
+
19
24
  def initialize(self):
20
25
  """Initialize database connection and session factory"""
21
26
  self.engine = create_engine(
22
- self.database_url, pool_pre_ping=True, pool_recycle=300, echo=False # Set to True for SQL debugging
27
+ self.database_url,
28
+ pool_pre_ping=True,
29
+ pool_recycle=300,
30
+ echo=False, # Set to True for SQL debugging
23
31
  )
24
32
  self.SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=self.engine)
25
33
  self._ensure_pgvector_extension()
26
34
 
27
35
  def create_schema(self, schema_name: str) -> None:
28
36
  """Create a new schema for a collection type"""
29
- with self.engine.connect() as conn:
37
+ with self._require_engine().connect() as conn:
30
38
  conn.execute(text(f"CREATE SCHEMA IF NOT EXISTS {schema_name}"))
31
39
  conn.commit()
32
40
 
@@ -37,12 +45,12 @@ class DatabaseManager:
37
45
  # Ensure all tables in this base class use the specified schema
38
46
  for table in base_class.metadata.tables.values():
39
47
  table.schema = schema_name
40
- base_class.metadata.create_all(self.engine, checkfirst=True)
48
+ base_class.metadata.create_all(self._require_engine(), checkfirst=True)
41
49
  self.logger.info(f"Created tables for schema: {schema_name}")
42
50
 
43
51
  def _ensure_pgvector_extension(self):
44
52
  """Ensure pgvector extension is available"""
45
- with self.engine.connect() as conn:
53
+ with self._require_engine().connect() as conn:
46
54
  conn.execute(text("CREATE EXTENSION IF NOT EXISTS vector"))
47
55
  conn.commit()
48
56
 
@@ -56,6 +64,8 @@ class DatabaseManager:
56
64
  # do stuff with the Session here
57
65
  ```
58
66
  """
67
+ if self.SessionLocal is None:
68
+ raise RuntimeError("DatabaseManager not initialized. Call initialize() first.")
59
69
  session = self.SessionLocal()
60
70
  try:
61
71
  yield session
@@ -23,7 +23,9 @@ class DocumentDatabaseManager(DatabaseManager):
23
23
 
24
24
  SCHEMA_PREFIX = "knowledge_base_"
25
25
 
26
- def __init__(self, database_url: str, schema_suffix: str, document_classes: List[Type[BaseDocument]]):
26
+ def __init__(
27
+ self, database_url: str, schema_suffix: str, document_classes: List[Type[BaseDocument]]
28
+ ):
27
29
  """
28
30
  Initialize a document-oriented database manager
29
31
 
@@ -79,7 +81,7 @@ class TempDocumentDatabaseManager(DocumentDatabaseManager):
79
81
  if not schema_name.startswith("temp_"):
80
82
  raise ValueError("Can only drop schemas with 'temp_' prefix for safety")
81
83
 
82
- with self.engine.connect() as conn:
84
+ with self._require_engine().connect() as conn:
83
85
  conn.execute(text(f"DROP SCHEMA IF EXISTS {schema_name} CASCADE"))
84
86
  conn.commit()
85
87
 
@@ -0,0 +1,5 @@
1
+ from pgvector_template.models.search import (
2
+ MetadataFilter as MetadataFilter,
3
+ RetrievalResult as RetrievalResult,
4
+ SearchQuery as SearchQuery,
5
+ )
@@ -1,6 +1,6 @@
1
1
  from dataclasses import dataclass, asdict
2
2
  from datetime import datetime
3
- from typing import Any, Literal, Type
3
+ from typing import Any, Literal
4
4
 
5
5
  from pydantic import BaseModel, ConfigDict, Field, model_validator
6
6
 
@@ -3,8 +3,7 @@ Document service layer combining corpus management and search capabilities.
3
3
  """
4
4
 
5
5
  from logging import getLogger
6
- from typing import Any, Generic, Type, TypeVar
7
- from uuid import UUID
6
+ from typing import Generic, Type, TypeVar
8
7
 
9
8
  from pydantic import BaseModel, Field
10
9
  from sqlalchemy.orm import Session
@@ -66,9 +66,9 @@ def validate_condition_compatibility(field_type: Type, condition: str) -> None:
66
66
  if origin is list:
67
67
  field_type = list
68
68
  elif len(args) > 0:
69
- field_type = args[0] # First non-None type
69
+ field_type = args[0] # ty: ignore[index-out-of-bounds]
70
70
 
71
- valid_conditions = {
71
+ valid_conditions: dict[type, set[str]] = {
72
72
  str: {"eq", "gt", "gte", "lt", "lte", "in", "exists"},
73
73
  int: {"eq", "gt", "gte", "lt", "lte", "exists"},
74
74
  float: {"eq", "gt", "gte", "lt", "lte", "exists"},
@@ -76,6 +76,6 @@ def validate_condition_compatibility(field_type: Type, condition: str) -> None:
76
76
  list: {"contains", "in", "exists"},
77
77
  }
78
78
 
79
- allowed = valid_conditions.get(field_type, {"eq", "exists"})
79
+ allowed: set[str] = valid_conditions.get(field_type, {"eq", "exists"})
80
80
  if condition not in allowed:
81
81
  raise ValueError(f"Condition '{condition}' not valid for field type {field_type.__name__}")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pgvector-template
3
- Version: 0.3.3
3
+ Version: 0.3.5
4
4
  Summary: Template library for flexible PGVector RAG implementations
5
5
  Author-email: DL <v49t9zpqd@mozmail.com>
6
6
  License: MIT
@@ -21,7 +21,8 @@ Requires-Dist: pytest>=7.0.0; extra == "test"
21
21
  Requires-Dist: pytest-cov>=4.0.0; extra == "test"
22
22
  Requires-Dist: python-dotenv>=1.0.0; extra == "test"
23
23
  Provides-Extra: dev
24
- Requires-Dist: black>=23.0.0; extra == "dev"
24
+ Requires-Dist: ruff>=0.9.0; extra == "dev"
25
+ Requires-Dist: ty>=0.0.1a0; extra == "dev"
25
26
  Provides-Extra: dist
26
27
  Requires-Dist: build>=1.2.2; extra == "dist"
27
28
  Requires-Dist: twine>=6.1.0; extra == "dist"
@@ -4,7 +4,8 @@ sqlalchemy>=2.0.0
4
4
  typing-extensions>=4.0.0
5
5
 
6
6
  [dev]
7
- black>=23.0.0
7
+ ruff>=0.9.0
8
+ ty>=0.0.1a0
8
9
 
9
10
  [dist]
10
11
  build>=1.2.2
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pgvector-template"
7
- version = "0.3.3"
7
+ version = "0.3.5"
8
8
  description = "Template library for flexible PGVector RAG implementations"
9
9
  authors = [{ name="DL", email="v49t9zpqd@mozmail.com" }]
10
10
  license = { text = "MIT" }
@@ -30,7 +30,8 @@ test = [
30
30
  "python-dotenv>=1.0.0",
31
31
  ]
32
32
  dev = [
33
- "black>=23.0.0",
33
+ "ruff>=0.9.0",
34
+ "ty>=0.0.1a0",
34
35
  ]
35
36
  dist = [
36
37
  "build>=1.2.2",
@@ -46,6 +47,9 @@ where = ["."] # Look for packages in the root directory
46
47
  include = ["pgvector_template*"] # Include all packages starting with pgvector_template
47
48
 
48
49
 
49
- [tool.black]
50
+ [tool.ruff]
50
51
  line-length = 100
51
- target-version = ["py311", "py312", "py313"]
52
+ target-version = "py311"
53
+
54
+ [tool.ty.src]
55
+ exclude = []
@@ -1 +0,0 @@
1
- from pgvector_template.models.search import *