quiver-client 0.22.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.
@@ -0,0 +1,51 @@
1
+ # --- Rust ---
2
+ /target/
3
+ **/target/
4
+ **/*.rs.bk
5
+ *.pdb
6
+
7
+ # --- Working notes / scratch (never committed) ---
8
+ /.scratch/
9
+
10
+ # --- Benchmark datasets (large; fetched on demand) ---
11
+ /bench/datasets/
12
+ /bench/results/*.local.*
13
+
14
+ # --- Node / SDKs ---
15
+ node_modules/
16
+ dist/
17
+ .turbo/
18
+ *.tsbuildinfo
19
+ .pnpm-store/
20
+
21
+ # --- Python / uv ---
22
+ __pycache__/
23
+ *.py[cod]
24
+ .venv/
25
+ .uv/
26
+ .pytest_cache/
27
+ .ruff_cache/
28
+ .mypy_cache/
29
+
30
+ # --- Secrets / local env ---
31
+ .env
32
+ .env.*
33
+ !.env.example
34
+ *.pem
35
+ *.key
36
+ *.crt
37
+ !**/testdata/**/*.pem
38
+ !**/testdata/**/*.crt
39
+
40
+ # --- Local data / runtime ---
41
+ /data/
42
+ /quiver-data/
43
+ *.qvr
44
+ *.wal
45
+
46
+ # --- OS / editor ---
47
+ .DS_Store
48
+ Thumbs.db
49
+ .idea/
50
+ .vscode/
51
+ *.swp
@@ -0,0 +1,140 @@
1
+ Metadata-Version: 2.4
2
+ Name: quiver-client
3
+ Version: 0.22.0
4
+ Summary: Python client for Quiver, the security-first vector database.
5
+ Project-URL: Repository, https://github.com/achref-soua/quiver
6
+ Author-email: Achref Soua <achref.soua@outlook.com>
7
+ License-Expression: AGPL-3.0-only
8
+ Keywords: ann,embeddings,quiver,vector-database
9
+ Requires-Python: >=3.10
10
+ Requires-Dist: httpx>=0.27
11
+ Provides-Extra: dcpe
12
+ Requires-Dist: cryptography>=42; extra == 'dcpe'
13
+ Provides-Extra: encryption
14
+ Requires-Dist: pynacl>=1.5; extra == 'encryption'
15
+ Provides-Extra: haystack
16
+ Requires-Dist: haystack-ai>=2.0; extra == 'haystack'
17
+ Provides-Extra: langchain
18
+ Requires-Dist: langchain-core>=1.0; extra == 'langchain'
19
+ Provides-Extra: llamaindex
20
+ Requires-Dist: llama-index-core>=0.11; extra == 'llamaindex'
21
+ Description-Content-Type: text/markdown
22
+
23
+ # quiver-client
24
+
25
+ The Python client for [Quiver](https://github.com/achref-soua/quiver), the security-first vector database. Embeddings are produced by the caller — Quiver is model-agnostic.
26
+
27
+ ## Install
28
+
29
+ ```bash
30
+ uv add quiver-client # or: pip install quiver-client
31
+ ```
32
+
33
+ ## Usage
34
+
35
+ ```python
36
+ from quiver import Client, Point
37
+
38
+ # Connect (use https:// and the api_key your server requires).
39
+ with Client("http://127.0.0.1:6333", api_key="your-api-key") as q:
40
+ q.create_collection("items", dim=3, metric="cosine")
41
+
42
+ q.upsert("items", [
43
+ Point("a", [0.1, 0.2, 0.3], {"color": "red"}),
44
+ Point("b", [0.9, 0.1, 0.0], {"color": "blue"}),
45
+ ])
46
+
47
+ hits = q.search(
48
+ "items",
49
+ [0.1, 0.2, 0.25],
50
+ k=5,
51
+ filter={"eq": {"field": "color", "value": "red"}},
52
+ )
53
+ for hit in hits:
54
+ print(hit.id, hit.score, hit.payload)
55
+ ```
56
+
57
+ `create_collection` also takes `index` (`hnsw` | `vamana` | `disk_vamana` | `ivf`)
58
+ and `pq_subspaces` to select the memory-frugal disk-resident path.
59
+
60
+ For late-interaction (ColBERT) retrieval, create a collection with
61
+ `multivector=True`, index documents as token sets with `upsert_documents`, and
62
+ rank them by MaxSim with `search_multi_vector`:
63
+
64
+ ```python
65
+ q.create_collection("papers", dim=128, metric="cosine", multivector=True)
66
+ q.upsert_documents("papers", [Document("p1", token_vectors, {"title": "…"})])
67
+ hits = q.search_multi_vector("papers", query_token_vectors, k=10)
68
+ ```
69
+
70
+ ## Client-side payload encryption
71
+
72
+ Seal payload fields with a key Quiver never sees (install
73
+ `quiver-client[encryption]`). The server stores and returns ciphertext it
74
+ cannot read; keep fields server-filterable by leaving them in cleartext:
75
+
76
+ ```python
77
+ from quiver import Client, Point
78
+ from quiver.encryption import PayloadCipher
79
+
80
+ cipher = PayloadCipher.from_hex("…64 hex chars…") # a dedicated key, never the at-rest one
81
+ with Client("http://127.0.0.1:6333", api_key="…") as q:
82
+ payload = {"tier": "gold", **cipher.seal({"ssn": "078-05-1120"})} # tier stays filterable
83
+ q.upsert("people", [Point("p1", [0.1, 0.2, 0.3], payload)])
84
+ hit = q.get("people", "p1")
85
+ secret = cipher.open(hit.payload) # -> {"ssn": "078-05-1120"}
86
+ ```
87
+
88
+ The envelope (XChaCha20-Poly1305) matches the Rust reference and the TypeScript
89
+ SDK byte-for-byte — see [client-side encryption](https://github.com/achref-soua/quiver/blob/main/docs/security/crypto.md#client-side-payload-encryption-adr-0012).
90
+
91
+ ## Encrypted vector search (DCPE, experimental)
92
+
93
+ Encrypt the **vectors** themselves so the server can run nearest-neighbour
94
+ search without ever seeing the plaintext embeddings (install
95
+ `quiver-client[dcpe]`). This is property-preserving (distance-comparison-
96
+ preserving) encryption — **experimental, L2-only, and not semantically secure**:
97
+ it leaks the approximate distance-comparison relation by design. Use a dedicated
98
+ key, and encrypt both the data and the queries with the same cipher.
99
+
100
+ ```python
101
+ from quiver import Client
102
+ from quiver.dcpe import DcpeCipher
103
+
104
+ cipher = DcpeCipher.from_hex("…64 hex chars…", approximation_factor=0.02)
105
+ with Client("http://127.0.0.1:6333", api_key="…") as q:
106
+ q.create_collection("vault", dim=8, metric="l2", vector_encryption="dcpe")
107
+ sealed = cipher.encrypt([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8])
108
+ q.upsert("vault", [{"id": "a", "vector": sealed.ciphertext}])
109
+ hits = q.search("vault", cipher.encrypt_query(my_query), k=10)
110
+ ```
111
+
112
+ See [ADR-0031](https://github.com/achref-soua/quiver/blob/main/docs/adr/0031-dcpe-vector-encryption.md)
113
+ and [docs/security/dcpe.md](https://github.com/achref-soua/quiver/blob/main/docs/security/dcpe.md).
114
+
115
+ ## LangChain
116
+
117
+ A LangChain `VectorStore` adapter ships in `quiver.langchain` (install
118
+ `quiver-client[langchain]`):
119
+
120
+ ```python
121
+ from quiver import Client
122
+ from quiver.langchain import QuiverVectorStore
123
+
124
+ store = QuiverVectorStore.from_texts(
125
+ texts, embedding, client=Client(api_key="…"),
126
+ collection="docs", index="disk_vamana", pq_subspaces=48,
127
+ )
128
+ docs = store.similarity_search("query", k=4)
129
+ ```
130
+
131
+ ## Development
132
+
133
+ ```bash
134
+ uv sync # create the venv and install dependencies
135
+ uv run pytest # run the test suite (HTTP mocked with respx)
136
+ ```
137
+
138
+ ## License
139
+
140
+ AGPL-3.0-only.
@@ -0,0 +1,118 @@
1
+ # quiver-client
2
+
3
+ The Python client for [Quiver](https://github.com/achref-soua/quiver), the security-first vector database. Embeddings are produced by the caller — Quiver is model-agnostic.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ uv add quiver-client # or: pip install quiver-client
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ ```python
14
+ from quiver import Client, Point
15
+
16
+ # Connect (use https:// and the api_key your server requires).
17
+ with Client("http://127.0.0.1:6333", api_key="your-api-key") as q:
18
+ q.create_collection("items", dim=3, metric="cosine")
19
+
20
+ q.upsert("items", [
21
+ Point("a", [0.1, 0.2, 0.3], {"color": "red"}),
22
+ Point("b", [0.9, 0.1, 0.0], {"color": "blue"}),
23
+ ])
24
+
25
+ hits = q.search(
26
+ "items",
27
+ [0.1, 0.2, 0.25],
28
+ k=5,
29
+ filter={"eq": {"field": "color", "value": "red"}},
30
+ )
31
+ for hit in hits:
32
+ print(hit.id, hit.score, hit.payload)
33
+ ```
34
+
35
+ `create_collection` also takes `index` (`hnsw` | `vamana` | `disk_vamana` | `ivf`)
36
+ and `pq_subspaces` to select the memory-frugal disk-resident path.
37
+
38
+ For late-interaction (ColBERT) retrieval, create a collection with
39
+ `multivector=True`, index documents as token sets with `upsert_documents`, and
40
+ rank them by MaxSim with `search_multi_vector`:
41
+
42
+ ```python
43
+ q.create_collection("papers", dim=128, metric="cosine", multivector=True)
44
+ q.upsert_documents("papers", [Document("p1", token_vectors, {"title": "…"})])
45
+ hits = q.search_multi_vector("papers", query_token_vectors, k=10)
46
+ ```
47
+
48
+ ## Client-side payload encryption
49
+
50
+ Seal payload fields with a key Quiver never sees (install
51
+ `quiver-client[encryption]`). The server stores and returns ciphertext it
52
+ cannot read; keep fields server-filterable by leaving them in cleartext:
53
+
54
+ ```python
55
+ from quiver import Client, Point
56
+ from quiver.encryption import PayloadCipher
57
+
58
+ cipher = PayloadCipher.from_hex("…64 hex chars…") # a dedicated key, never the at-rest one
59
+ with Client("http://127.0.0.1:6333", api_key="…") as q:
60
+ payload = {"tier": "gold", **cipher.seal({"ssn": "078-05-1120"})} # tier stays filterable
61
+ q.upsert("people", [Point("p1", [0.1, 0.2, 0.3], payload)])
62
+ hit = q.get("people", "p1")
63
+ secret = cipher.open(hit.payload) # -> {"ssn": "078-05-1120"}
64
+ ```
65
+
66
+ The envelope (XChaCha20-Poly1305) matches the Rust reference and the TypeScript
67
+ SDK byte-for-byte — see [client-side encryption](https://github.com/achref-soua/quiver/blob/main/docs/security/crypto.md#client-side-payload-encryption-adr-0012).
68
+
69
+ ## Encrypted vector search (DCPE, experimental)
70
+
71
+ Encrypt the **vectors** themselves so the server can run nearest-neighbour
72
+ search without ever seeing the plaintext embeddings (install
73
+ `quiver-client[dcpe]`). This is property-preserving (distance-comparison-
74
+ preserving) encryption — **experimental, L2-only, and not semantically secure**:
75
+ it leaks the approximate distance-comparison relation by design. Use a dedicated
76
+ key, and encrypt both the data and the queries with the same cipher.
77
+
78
+ ```python
79
+ from quiver import Client
80
+ from quiver.dcpe import DcpeCipher
81
+
82
+ cipher = DcpeCipher.from_hex("…64 hex chars…", approximation_factor=0.02)
83
+ with Client("http://127.0.0.1:6333", api_key="…") as q:
84
+ q.create_collection("vault", dim=8, metric="l2", vector_encryption="dcpe")
85
+ sealed = cipher.encrypt([0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8])
86
+ q.upsert("vault", [{"id": "a", "vector": sealed.ciphertext}])
87
+ hits = q.search("vault", cipher.encrypt_query(my_query), k=10)
88
+ ```
89
+
90
+ See [ADR-0031](https://github.com/achref-soua/quiver/blob/main/docs/adr/0031-dcpe-vector-encryption.md)
91
+ and [docs/security/dcpe.md](https://github.com/achref-soua/quiver/blob/main/docs/security/dcpe.md).
92
+
93
+ ## LangChain
94
+
95
+ A LangChain `VectorStore` adapter ships in `quiver.langchain` (install
96
+ `quiver-client[langchain]`):
97
+
98
+ ```python
99
+ from quiver import Client
100
+ from quiver.langchain import QuiverVectorStore
101
+
102
+ store = QuiverVectorStore.from_texts(
103
+ texts, embedding, client=Client(api_key="…"),
104
+ collection="docs", index="disk_vamana", pq_subspaces=48,
105
+ )
106
+ docs = store.similarity_search("query", k=4)
107
+ ```
108
+
109
+ ## Development
110
+
111
+ ```bash
112
+ uv sync # create the venv and install dependencies
113
+ uv run pytest # run the test suite (HTTP mocked with respx)
114
+ ```
115
+
116
+ ## License
117
+
118
+ AGPL-3.0-only.
@@ -0,0 +1,51 @@
1
+ [project]
2
+ name = "quiver-client"
3
+ version = "0.22.0"
4
+ description = "Python client for Quiver, the security-first vector database."
5
+ readme = "README.md"
6
+ requires-python = ">=3.10"
7
+ license = "AGPL-3.0-only"
8
+ authors = [{ name = "Achref Soua", email = "achref.soua@outlook.com" }]
9
+ keywords = ["vector-database", "ann", "embeddings", "quiver"]
10
+ dependencies = ["httpx>=0.27"]
11
+
12
+ [project.optional-dependencies]
13
+ # Client-side payload encryption (quiver.encryption). Install with
14
+ # `pip install quiver-client[encryption]`.
15
+ encryption = ["pynacl>=1.5"]
16
+ # Client-side DCPE vector encryption (quiver.dcpe, ADR-0031). Install with
17
+ # `pip install quiver-client[dcpe]`. Uses ChaCha20 from `cryptography`.
18
+ dcpe = ["cryptography>=42"]
19
+ # The LangChain VectorStore adapter (quiver.langchain). Install with
20
+ # `pip install quiver-client[langchain]`.
21
+ langchain = ["langchain-core>=1.0"]
22
+ # The LlamaIndex VectorStore adapter (quiver.llamaindex). Install with
23
+ # `pip install quiver-client[llamaindex]`.
24
+ llamaindex = ["llama-index-core>=0.11"]
25
+ # The Haystack DocumentStore + retriever (quiver.haystack). Install with
26
+ # `pip install quiver-client[haystack]`.
27
+ haystack = ["haystack-ai>=2.0"]
28
+
29
+ [project.urls]
30
+ Repository = "https://github.com/achref-soua/quiver"
31
+
32
+ [build-system]
33
+ requires = ["hatchling"]
34
+ build-backend = "hatchling.build"
35
+
36
+ [tool.hatch.build.targets.wheel]
37
+ packages = ["src/quiver"]
38
+
39
+ [dependency-groups]
40
+ dev = [
41
+ "pytest>=8",
42
+ "respx>=0.21",
43
+ "pynacl>=1.5",
44
+ "cryptography>=42",
45
+ "langchain-core>=1.0",
46
+ "llama-index-core>=0.11",
47
+ "haystack-ai>=2.0",
48
+ ]
49
+
50
+ [tool.pytest.ini_options]
51
+ testpaths = ["tests"]
@@ -0,0 +1,69 @@
1
+ # SPDX-License-Identifier: AGPL-3.0-only
2
+ """Quiver — Python client for the security-first vector database.
3
+
4
+ Example::
5
+
6
+ from quiver import Client, Point
7
+
8
+ with Client(api_key="…") as q:
9
+ q.create_collection("items", dim=3, metric="cosine")
10
+ q.upsert("items", [Point("a", [0.1, 0.2, 0.3], {"tag": "x"})])
11
+ hits = q.search("items", [0.1, 0.2, 0.3], k=5)
12
+ """
13
+
14
+ from .client import (
15
+ TEXT_KEY,
16
+ Client,
17
+ CollectionInfo,
18
+ Document,
19
+ DocumentMatch,
20
+ FilterableField,
21
+ Match,
22
+ Point,
23
+ QuiverError,
24
+ SparseVector,
25
+ )
26
+ from .async_client import AsyncClient
27
+ from .rerank import RerankResult, rerank
28
+ from .dcpe import DcpeCipher, DcpeError, EncryptedVector
29
+ from .encryption import ENVELOPE_KEY, PayloadCipher, PayloadError, is_sealed
30
+ from .vector import (
31
+ VECTOR_ENVELOPE_KEY,
32
+ MalformedVectorEnvelopeError,
33
+ NotEncryptedVectorError,
34
+ VectorCipher,
35
+ VectorDecryptError,
36
+ VectorError,
37
+ is_sealed_vector,
38
+ )
39
+
40
+ __all__ = [
41
+ "Client",
42
+ "AsyncClient",
43
+ "Point",
44
+ "Match",
45
+ "SparseVector",
46
+ "TEXT_KEY",
47
+ "rerank",
48
+ "RerankResult",
49
+ "Document",
50
+ "DocumentMatch",
51
+ "CollectionInfo",
52
+ "FilterableField",
53
+ "QuiverError",
54
+ "PayloadCipher",
55
+ "PayloadError",
56
+ "is_sealed",
57
+ "ENVELOPE_KEY",
58
+ "DcpeCipher",
59
+ "DcpeError",
60
+ "EncryptedVector",
61
+ "VectorCipher",
62
+ "VectorError",
63
+ "VectorDecryptError",
64
+ "NotEncryptedVectorError",
65
+ "MalformedVectorEnvelopeError",
66
+ "is_sealed_vector",
67
+ "VECTOR_ENVELOPE_KEY",
68
+ ]
69
+ __version__ = "0.19.0"