Skip to main content
Pre-release

This release is a pre-release and may not be stable for production use.

BriskDB for Python

This package runs BriskDB's sharded SQLite engine in the Python process. It starts no listener by default and never installs a signal handler or global logger. A database can optionally expose its exact engine through host-controlled data HTTP, administration HTTP, and PostgreSQL listeners.

Tagged releases publish compiler-free wheels for CPython 3.9–3.14 on supported macOS and Linux targets:

python -m pip install --only-binary=:all: briskdb

Document commands use PyMongo's public BSON classes as an optional companion:

python -m pip install --only-binary=:all: briskdb
python -m pip install pymongo

The BriskDB wheel does not require or import PyMongo for SQL-only applications.

To build the current checkout from source, use Python 3.9+ and Rust 1.85+:

python -m pip install ./python
import briskdb

db = briskdb.open("./data", shards=4)
session = db.session(routing_key="account-1")
session.migrate("CREATE TABLE notes (id INTEGER PRIMARY KEY, body TEXT NOT NULL)")
session.execute("INSERT INTO notes VALUES (?1, ?2)", [1, "hello"])
print(session.query("SELECT body FROM notes WHERE id = ?1", [1]))
session.close()
db.close()

Patch PyMongo for local testing

The alpha.7 wheel includes briskdb.patch(), a TinyMongo-style context manager/decorator. Install its optional pinned driver companion:

python -m pip install --only-binary=:all: 'briskdb[pymongo]==0.1.0a7'
# Or build a repository checkout with Rust 1.85+:
python -m pip install './python[pymongo]'
# For a supplied test wheel (replacing any same-version older build):
python -m pip install --force-reinstall './briskdb-...whl[pymongo]'
import briskdb
import pymongo

with briskdb.patch():  # isolated temporary SQLite files, not RAM-only
    writer = pymongo.MongoClient("mongodb://ignored.example.com")
    reader = pymongo.MongoClient()
    writer.app.users.insert_one({"_id": 1, "name": "Ada", "score": 9})
    assert reader.app.users.find_one({"_id": 1})["name"] == "Ada"
# Clients close, PyMongo is restored, and the temporary files are removed.

Keep data with briskdb.patch(folder="./test-data", shards=4), also usable as a synchronous test decorator. New roots default to four shards; reopening detects the stored layout unless an explicit count is supplied. Persistent folders are never deleted. Nested default scopes are isolated; managed clients and scopes using one canonical persistent path share one process-local engine until its last owner closes. Unrelated native briskdb.open() handles still obey the ordinary schema/multi-process ownership restrictions.

import asyncio
import briskdb
import pymongo

async def test_application():
    async with briskdb.patch(folder="./async-test-data"):
        async with pymongo.AsyncMongoClient() as client:
            await client.app.users.update_one(
                {"_id": 1}, {"$set": {"name": "Ada"}}, upsert=True
            )
            print(await client.app.users.find({}).sort("name", 1).to_list())

asyncio.run(test_application())

Async clients require async with briskdb.patch() for awaited cleanup. Async scope startup/cleanup runs off the event loop and drains even on caller cancellation. Async decorators and async clients in synchronous scopes are rejected explicitly. Enter the patch before importing application/ODM modules that capture client aliases, and retain it for the full application lifetime. Only top-level pymongo.MongoClient/AsyncMongoClient are replaced. Existing clients, earlier constructor aliases and explicit PyMongo submodule imports are unchanged and may still contact their original server. Process-global scopes cannot overlap across threads/tasks; nesting must unwind in order.

Direct PyMongo-shaped clients

from briskdb import MongoClient, DESCENDING

with MongoClient(folder="./app-data", shards=4) as client:
    print(list(client.app.users.find({"score": {"$gte": 5}}).sort("score", DESCENDING)))

briskdb.AsyncMongoClient provides async with and awaited operations/close. Direct async-client construction opens storage synchronously; an async patch scope offloads startup. A positional filesystem path, briskdb_folder, and migration aliases tinymongo_folder, tinymongo_path, foldername, and sqlite_shards are accepted. Direct clients default to BRISKDB_HOME or ./briskdb-data; use explicit close or context managers. client.briskdb_path reports the root. ASCENDING, DESCENDING, ReturnDocument, IndexModel, and briskdb.errors support common client-side call sites.

Both forms use real PyMongo 4.17.0 collections, cursors, results and exceptions with one private loopback Mongo listener over the bundled Rust engine. No HTTP/admin/SQL port or separate process starts. Supplied hosts/SRV destinations, credentials, TLS, proxy and replica-set settings are ignored for this explicit local replacement. URI database names and ordinary driver/codec settings are retained and validated by PyMongo; automatic encryption is rejected, not bypassed. There is no remote fallback. The unauthenticated loopback socket is not a security boundary against other local users/processes.

Existing BriskDB Mongo query/resource limits still apply. This does not add transactions, change streams, TinyMongo-only metadata helpers or alternative memory/JSON/DuckDB/remote backends. backend="sqlite"/"sqlite-sharded" are accepted migration spellings; backend="memory" is rejected instead of calling temporary files RAM. Use fresh BriskDB roots, not TinyMongo database files, and spawned processes with newly constructed handles, never inherited clients after fork(). PyMongo remains optional for SQL-only use and unentered patch objects.

After installing a test wheel, run python python/examples/mongo/patch.py from the repository (or copy that script elsewhere). It exercises sync queries, unique indexes, updates, async access and persisted reopen without a daemon.

Query a remote BriskDB server through standard sqlite3 (read-only preview)

The same wheel includes an original native SQLite virtual-table addon and its remote client; this is not a VFS or a replacement for Python's sqlite3 driver. Against an explicitly enabled BriskDB remote listener:

import os
import sqlite3
import briskdb

conn = sqlite3.connect(":memory:")
with briskdb.attach_remote(conn, "https://db.example.com", token=os.environ["BRISKDB_TOKEN"]):
    print(conn.execute("SELECT * FROM remote.users WHERE id = ?", (123,)).fetchall())
conn.close()

Start the dedicated, authenticated listener against an existing engine with db.serve(admin=None, sqlite_remote_token=token, sqlite_remote_tables=["users"]). It serves only allowlisted tables; the normal /v1/query and /v1/execute routes are absent. Publish its loopback address through a trusted HTTPS reverse proxy for network access. Do not publish a separate admin/ordinary HTTP listener. Tokens should be generated with secrets.token_urlsafe(32) and kept out of source.

Registered logical tables use BriskDB's normal shard placement. Uncataloged legacy databases require an explicit server-side sqlite_remote_routing_key= and expose only that routed shard, reported as attachment.scope == "legacy-shard"; registered tables report "logical". A routing key is not a row-level authorization filter: every allowlisted table row on that shard is readable.

This preview supports bounded reads, parameters, aggregates, local SQL functions, and joins with local tables. Each scan is limited to 4,096 rows, 1 MiB of engine results and an 8 MiB encoded response (or stricter engine settings). No predicate, projection, or LIMIT pushdown yet: even LIMIT 1 must fit the full table scan. Oversized results fail, never truncate. Reads across tables/shards are not a transaction snapshot. Writes, hidden rowids, remote DDL and transaction mapping are not implemented. See the API contract and host SQLite requirements.

Enable native BSON commands per database handle. The default standard UUID representation uses subtype 4; legacy and unspecified modes are documented in the value conversion contract.

from bson import ObjectId
import briskdb

with briskdb.open("./data", shards=4, documents=True) as db:
    with db.session() as session:
        session.create_collection("app", "notes")
        note_id = ObjectId()
        session.insert_one(
            "app", "notes", {"_id": note_id, "body": "hello"}
        )
        result = session.find("app", "notes", {"_id": note_id})
        print(result["documents"])

The document API supports collection/index metadata, single-document insertion with generated IDs, BSON find/count/distinct, filtered deletes, replacements, $set/$unset/$min/$max/$pop/$rename/$addToSet/$pullAll/$push/$pull/$inc updates, and retained cursors through synchronous and asyncio sessions. Find-one-and-delete returns a projected before-image; find-one-and-replace/update support sorted projected before/after images. Return size/depth checks precede mutation. Push supports $each, $position, $sort, and $slice in fixed insertion-sort-slice order, with bounded growth and stable whole-BSON/document-field sorting. Pull removes literal values or applies bounded query predicates to array members without creating missing fields. Increment preserves numeric width, rejects integer overflow, handles Decimal128 promotion and rounded no-ops, and safely updates concurrent counters. replace_one(..., upsert=True) inserts on no match, retaining an equality-bound query ID or generating an ObjectId when the replacement omits one. Insertions return zero matched/modified counts and did_upsert=True, including null IDs; matches return did_upsert=False. Native upserts require an existing collection. Reply and document bounds precede insertion; same-ID races update the winner. update_one and update_many also accept upsert=True: positive direct/$eq equalities (including $and clauses and dotted object paths) seed the new document, then operators run. Conflicting equality paths fail before insertion; range, regex, and alternative predicates do not supply values. Operator timestamps stay literal. An unbound _id can be supplied by the update; otherwise one is generated after applying operators. find_one_and_replace and find_one_and_update accept upsert=True too. Their results retain kind: "document" and add did_upsert and upserted_id; an inserted null ID is distinct from no insertion. The default before-image is None on insertion, while return_document=True returns the projected inserted document. Matched images, including {}, report did_upsert=False. The ID metadata and image share the pre-commit result budget. Continue a non-null result["cursor_id"] with session.get_more(database, collection, cursor_id, batch_size=101); stop early with session.kill_cursor(database, collection, cursor_id). Cursors belong to the creating session and are released on session close. find(..., batch_size=0) opens an empty initial batch. Pages preserve global natural order, not a snapshot under concurrent writes. Request result limits still fail the whole command if exceeded. Pass projection={"body": 1, "_id": 0} or projection=["body"] to select returned fields; nested/array paths and exclusion are supported without mutating stored documents. The projection persists across cursor batches. Pass sort={"priority": -1, "_id": 1} for global BSON sorting before skip/limit and projection; the sort persists across cursor batches. Stable ties use natural order. Sorted pages use bounded key windows and rescan until sorted indexes exist; large skips may need repeated scans. create_index(database, collection, {"body": 1, "rank": -1}) now generates body_1_rank_-1; name= is optional in both synchronous and asyncio APIs. Numeric direction aliases normalize to Int32, while malformed/duplicate paths, invalid directions, reserved names and oversized definitions fail before catalog changes. Explicit names remain supported. Secondary declarations start pending_build. session.build_index(database, collection, name) explicitly builds a declared index and marks it Ready after every shard commits; later document writes maintain its entries transactionally. It requires sole-process ownership; interrupted builds require reopening for cleanup and retry. Non-unique indexes accept nested objects, arrays and other valid BSON values, retaining conservative candidates when an equality key cannot be generated. Unique indexes retain the stricter supported key subset. Ready indexes provide conservative scalar-equality candidates; unsupported shapes still scan. unique=True indexes validate existing records before activation and enforce canonical keys across shards on every write, raising UniqueViolationError on conflicts. Use create_built_index(..., unique=True) to declare and build in one call. The built-in _id_ remains ready and enforced, but its redeclaration is not part of this checkpoint; other update operators, additional aggregation expressions, and bulk-write Python helpers remain future work. Multi-delete/update commit one shard at a time; failure rolls back the current shard, not earlier commits. See the write boundaries.

session.drop_collection(database, collection) and session.drop_database(database) return {"kind": "namespace_dropped", "existed": bool, "request_id": ..., "plan": None}. Async sessions expose the same methods and request controls. Missing targets return false. Drops preserve unrelated namespaces and SQL tables; dropping the final collection removes its empty logical database. Retained cursors cannot read a recreated collection. Drops require sole-process ownership. If interrupted after durable intent, the root remains fenced until reopen finishes deletion; cancellation does not promise rollback. See document storage.

session.aggregate(database, collection, pipeline, batch_size=101) accepts a list of $match, $sort, $skip, $limit, $count, $project, $set, $addFields, $unset, and $group stages and returns the same cursor shape as find, with get_more/kill_cursor continuation and cleanup. The async session has the same method and request controls. Simple pipelines stream across batches; count retains a counter and sort uses bounded working memory; group retains bounded accumulator states. There is no disk spill or snapshot guarantee. A zero batch size defers input reads. Pipeline conversion uses one 16-MiB BSON/64-MiB heap budget; execution has 65,536 consumed-input and four-million-step bounds over the whole cursor. Projection stages support field references, arrays, $literal, $ifNull, $size, and $$REMOVE. Assignments read the original input; no pipeline stage changes stored documents. A later limit stops unused expression evaluation, including after a sort. Each transform specification has a 1-MiB/4,096-node/depth-100 bound; per-row allocation-work and step limits reject computed-output amplification. Group keys may be literal BSON, field references, or computed objects/arrays and the existing $literal/$ifNull/$size expressions. Variables such as $$REMOVE and $$ROOT are not supported in group expressions (use $literal to retain such strings as data). Supported accumulators are $addToSet, $avg, $first, $last, $max, $min, $push, and $sum. They share global input order, BSON identity, Decimal128 arithmetic, memory limits and cursor cleanup with Rust and PyMongo; see the numeric and grouping contract for result-type boundaries. Group results must each fit BSON before delivery. Native count_documents() remains the separate direct engine count helper; PyMongo's version now runs its actual constant-key aggregation pipeline, with aggregation row/work limits and an error for explicit limit=0.

Pass shards when creating a data directory. Later calls may omit it and use the count stored in the manifest. Passing the wrong count raises FailedPreconditionError; omitting it for new/empty storage asks you to choose one without creating files.

Resource limits can be validated before the database opens:

config = briskdb.Config(shards=4, max_result_rows=5_000)
db = briskdb.open("./data", config=config)

To serve that same open database to browser/HTTP and PostgreSQL clients:

with briskdb.open("./data") as db:
    with db.serve(postgres="127.0.0.1:0") as server:
        print(server.data_address)      # data API; port 0 is resolved
        print(server.http_address)      # compatibility alias for data_address
        print(server.admin_address)     # health, metrics, and browser
        print(server.postgres_address)

The data and administration HTTP listeners are separate and loopback-only. Administration defaults to another operating-system-selected loopback port; pass admin=None to disable /health, /metrics, /v1/admin/*, and the browser. Unauthenticated PostgreSQL is also loopback-only. To expose PostgreSQL on another address, pass postgres_tls_cert, postgres_tls_key, postgres_user, and postgres_password_file to serve(); TLS plus SCRAM-SHA-256 are then required for every database session. The password is read from the file, never passed as a Python string. Closing a server leaves the database usable; closing the database first closes all of its attached servers. The asyncio API provides await db.serve() and an AsyncServer context manager with the same lifecycle.

For PyMongo clients, the same wheel includes an optional Mongo listener:

from pymongo import MongoClient

with briskdb.open("./data", documents=True) as db:
    with db.serve(mongo="127.0.0.1:0") as server:
        with MongoClient(f"mongodb://{server.mongo_address}") as client:
            client.app.notes.update_one(
                {"_id": 123}, {"$set": {"body": "hello"}}, upsert=True
            )
            print(client.app.notes.find_one({"_id": 123}))

This uses the same BSON collections as native document sessions, not SQL tables. Mongo is disabled by default (mongo=None), requires documents=True, and is unauthenticated/loopback-only. Neither PostgreSQL credentials nor SQLite remote tokens authenticate Mongo. Do not publicly proxy this port. AsyncDatabase.serve accepts the same option and AsyncServer.mongo_address reports its bound address. PyMongo is still optional for importing BriskDB and for SQL-only applications. See the Mongo compatibility contract for the supported subset and limits; this is not a full MongoDB server.

Database and session handles own their native resources, close() is idempotent, and blocking engine work releases Python's GIL. Dropping live handles during interpreter shutdown is also safe.

Multiple independently spawned Python processes may open the same ready data directory on one local Linux or macOS host. Each process must create its own handle; use multiprocessing.get_context("spawn"), not an inherited live handle after fork(). Schema changes require every peer to close first and otherwise return retryable BusyError. See the multi-process contract.

Synchronous handles support with; the asyncio facade keeps engine work off the event loop and propagates task cancellation into Rust:

async with await briskdb.open_async("./data") as db:
    async with await db.session(routing_key="account-1") as session:
        rows = await session.query("SELECT body FROM notes WHERE id = ?1", [1])

See sync and asyncio usage for transactions, streaming cursors, deadlines, cancellation, thread/task safety, and the intentionally unclaimed DB-API compatibility surface. The API reference, platform matrix, and serverless-shaped warm-handler example define the supported package surface and its current boundaries.

This is an alpha API. SQL supports None, bool, bounded integers, float, str, bytes-like values, and exact decimal.Decimal conversion with explicit errors when SQLite cannot store a value losslessly. See the executable value and exception contract for boundaries and the stable BriskDBError hierarchy.

The extension uses the host-controlled listeners and documents Rust features and does not include the daemon CLI, signal handler, or logging subscriber. Enabling documents starts no MongoDB listener.

Release files for briskdb 0.1.0a7

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

Source distribution (sdist)

Source distribution for briskdb 0.1.0a7
File Size Uploaded
briskdb-0.1.0a7.tar.gz 4.7 MB Details

Built distributions (wheels)

Table of built distributions (wheels) for briskdb 0.1.0a7
File
briskdb-0.1.0a7-cp39-abi3-manylinux_2_28_x86_64.whl CPython 3.9 abi3 Linux glibc 2.28+ x86-64 Details
briskdb-0.1.0a7-cp39-abi3-manylinux_2_28_aarch64.whl CPython 3.9 abi3 Linux glibc 2.28+ ARM64 Details
briskdb-0.1.0a7-cp39-abi3-macosx_11_0_x86_64.whl CPython 3.9 abi3 macOS 11.0+ x86-64 Details
briskdb-0.1.0a7-cp39-abi3-macosx_11_0_arm64.whl CPython 3.9 abi3 macOS 11.0+ ARM64 Details

Total release size: 53.5 MB

Release files / briskdb-0.1.0a7.tar.gz

Download URL briskdb-0.1.0a7.tar.gz
Size 4.7 MB
Tags Source
SHA-256 checksum
How to use checksums
68fd3f7d59ad6e60a1ff85b801d333e820de9b796982692c2c3cb143d799e39a
BLAKE2b-256 checksum
How to use checksums
534a2fd2f3aa040760e64d3fea8a08fee254c58e664ebea52fd6810067a1b306
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / briskdb-0.1.0a7-cp39-abi3-manylinux_2_28_x86_64.whl

Download URL briskdb-0.1.0a7-cp39-abi3-manylinux_2_28_x86_64.whl
Size 12.8 MB
Tags CPython 3.9 Linux glibc 2.28+ x86-64 abi3
SHA-256 checksum
How to use checksums
671e515a47acfda1c44bffe5f9de76e8fbb1dfa1fe79085a11f3f21055f45230
BLAKE2b-256 checksum
How to use checksums
20e969f040148854aabd5c4bbde27bdcf13be6e574324879785013a0f09c4c5f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / briskdb-0.1.0a7-cp39-abi3-manylinux_2_28_aarch64.whl

Download URL briskdb-0.1.0a7-cp39-abi3-manylinux_2_28_aarch64.whl
Size 12.1 MB
Tags CPython 3.9 Linux glibc 2.28+ ARM64 abi3
SHA-256 checksum
How to use checksums
94cb0b19b320b4607e383e9d7aa52a73eb3d7c0cec960326a8753ce5c5e882d8
BLAKE2b-256 checksum
How to use checksums
bccb3a9b330e99c5a5642c3c2913786cd783a30cc6253b21f2a6254d01638fda
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / briskdb-0.1.0a7-cp39-abi3-macosx_11_0_x86_64.whl

Download URL briskdb-0.1.0a7-cp39-abi3-macosx_11_0_x86_64.whl
Size 12.3 MB
Tags CPython 3.9 abi3 macOS 11.0+ x86-64
SHA-256 checksum
How to use checksums
f6d726a900a403c37317ca551e9f01b9ec1fdf87ad8053f7eb6b977790e51392
BLAKE2b-256 checksum
How to use checksums
b57729a156e7beb180a7fa3964f27ffb64867f3c8d59ef0fb318f1ee2823c6fc
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14

Release files / briskdb-0.1.0a7-cp39-abi3-macosx_11_0_arm64.whl

Download URL briskdb-0.1.0a7-cp39-abi3-macosx_11_0_arm64.whl
Size 11.6 MB
Tags CPython 3.9 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
6e1c750de5021cd6a15f7bd49aa68af9d71e9f0db58a72684a97ab044a3d947b
BLAKE2b-256 checksum
How to use checksums
f5d439b1e844d94807c439a3025e4e6df00da974831e6ec60f825604f4d3fee2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.13.14
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