Skip to main content

fenecdb for Python

A client for fenec-server's HTTP endpoint (fenec-server --http <address>), and vector stores for LangChain and LlamaIndex on top of it.

pip install "fenecdb[langchain]"      # or "fenecdb[llama-index]"
from fenecdb import Client

db = Client("http://127.0.0.1:8080", token="...")
db.query("get articles select title near embed $1 limit 5", [[0.1, 0.2, 0.3]])

Or the query builder writes the statement -- every value a parameter, every name checked -- the same text the JavaScript, Go and .NET builders make of the same chain:

from fenecdb import or_

docs = db.collection("articles")
rows = (docs.select("title")
            .where("year", ">=", 2024)
            .where(or_({"lang": "tr"}, {"tags": {"has": "rust"}}))
            .near("embed", [0.1, 0.2, 0.3], ef=64)
            .limit(5)
            .rows())
docs.insert({"title": "Dunes", "year": 2021})
docs.where("year", "<", 2000).delete()        # no filter: refused unless all=True
docs.where("lang", "tr").count()

To see the text and parameters a chain builds, for logging or a test, to_fenecql() returns them and runs nothing: docs.select("title").limit(5).to_fenecql() is ("get articles select title limit 5", []). A query needs no call to it before it runs.

In an event loop -- FastAPI, aiohttp, an agent -- AsyncClient makes the same calls awaited, over one kept-alive connection, the standard library alone:

from fenecdb import AsyncClient

async with AsyncClient("http://127.0.0.1:8080", token="...") as db:
    rows = await db.query("get articles select title near embed $1 limit 5", [[0.1, 0.2, 0.3]])
    await db.batch([("put articles {title: $1}", ["a"]), ("put articles {title: $1}", ["b"])])
    rows = await db.collection("articles").where("year", ">=", 2024).rows()

Every write on the server's disk (fenec-server --cdc), for a consumer whose cursor the server keeps -- each batch committed once the loop comes back for the next, so each write comes at least once -- and the same handed on to another program or a webhook:

for batch in db.follow("search-index"):
    for change in batch:               # {"seq", "at", "collection", "op", "id", "doc"}
        index(change)
python -m fenecdb.relay http://127.0.0.1:8080 --consumer kafka | kcat -P -b broker:9092 -t fenec
from fenecdb.langchain import FenecVectorStore

store = FenecVectorStore(embeddings, "docs", url="http://127.0.0.1:8080", token="...",
                         metadata_fields={"source": "text"})
store.add_documents(documents)
store.similarity_search("how do I compact", k=4, filter={"source": "handbook"})
from fenecdb.llama_index import FenecVectorStore
from llama_index.core import StorageContext, VectorStoreIndex

store = FenecVectorStore("docs", url="http://127.0.0.1:8080", token="...")
index = VectorStoreIndex.from_documents(
    documents, storage_context=StorageContext.from_defaults(vector_store=store)
)

A document or node is a row -- its id, text, metadata as JSON and vector under @hnsw -- in a collection created on the first write. Fields named in metadata_fields get columns of their own under @hash, and filters over them are answered by the index before the search runs.

With full_text=True the text is indexed for BM25 too, and both stores search by the words alone or by the words and the vector fused -- LangChain's mode="text" and mode="hybrid", LlamaIndex's TEXT_SEARCH and HYBRID. quant="int8" or "bit" keeps the graph over codes.

store = FenecVectorStore(embeddings, "docs", url=..., token=..., full_text=True)
store.similarity_search("how do I compact", k=4, mode="hybrid")

./run-tests.sh runs LangChain's standard vector store suite and the tests LlamaIndex's own integrations run against a fenec-server it builds and starts, and the query builder against every case of integrations/builder-golden.json. Full reference: https://fenecdb.com/docs/integrations

Metadata

Release files for fenecdb 0.1.10

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for fenecdb 0.1.10
File Size Uploaded
fenecdb-0.1.10.tar.gz 37.8 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for fenecdb 0.1.10
File Interpreter ABI Platform
fenecdb-0.1.10-py3-none-any.whl Python 3 none any Details

Total release size: 68.8 kB

Release files / fenecdb-0.1.10.tar.gz

Download URL fenecdb-0.1.10.tar.gz
Size 37.8 kB
Tags Source
SHA-256 checksum
How to use checksums
190e820b4f3441b29efdf969c4978aaa936903d87382c58d0fc113dd1ad192e4
BLAKE2b-256 checksum
How to use checksums
d048f46b8ef1cda06e056687cc53c73039503b6de365031d1f7188064bc7a78d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / fenecdb-0.1.10-py3-none-any.whl

Download URL fenecdb-0.1.10-py3-none-any.whl
Size 31.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
541a0b797cb7bc386a2622dc8b7cde98a47d71aa6ec727a40e642e74c28b2db5
BLAKE2b-256 checksum
How to use checksums
da8b39b5ba86eaef99525e931d70b667103afc7b0ab93f6e1440332b4de63d0d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release history Release notifications | RSS feed

This release

0.1.10 This release

2 release files

0.1.9

2 release files

0.1.8

2 release files

0.1.7

2 release files

0.1.6

2 release files

0.1.5

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page