Local-first database for Python — documents, cache, queue, FTS, vectors over one SQLite file. The Python port of monlite; reads/writes the same .db as the TypeScript packages.
Project description
monlite (Python)
The local-first database for Python — documents, cache, durable queue, cron, and full-text search over one SQLite file, with a pure-standard-library core. No dependencies required.
monlite is the Python port of monlite. It reads and writes the same
.db file as the TypeScript @monlite/* packages — same documents, change feed, _kv/sorted-set
tables, _jobs queue, _schedules, and FTS5 index — so Python ingests or embeds while Node
serves (or any split you like). Every table layout is byte-compatible and covered by an interop
suite that round-trips a file between the two runtimes.
pip install monlite
Quick start
from monlite import create_db, kv
db = create_db("app.db")
users = db.collection("users")
users.create({"name": "Ali", "age": 30, "tags": ["admin"]})
users.create_many([{"name": "Sara", "age": 25}, {"name": "Omar", "age": 40}])
adults = users.find_many(where={"age": {"gte": 18}}, order_by={"age": "asc"})
ali = users.find_first(where={"name": "Ali"})
users.update({"_id": ali["_id"]}, {"$inc": {"age": 1}, "$push": {"tags": "vip"}})
count = users.count(where={"role": "admin"})
cache = kv(db)
cache.set("session:42", {"user": "ali"}, ttl=60_000)
Query operators
Mongo/Prisma-style, mirroring the TypeScript API (snake_case method names):
where={"age": {"gte": 18, "lt": 65}}
where={"role": {"in": ["admin", "editor"]}, "name": {"not": "root"}}
where={"name": {"contains": "ali", "mode": "insensitive"}}
where={"sku": {"startsWith": "AB", "endsWith": "-1"}}
where={"email": {"regex": r"@example\.com$"}}
where={"tags": {"has": "admin"}} # array contains
where={"items": {"elemMatch": {"qty": {"gte": 5}}}} # any array element matches
where={"OR": [{"role": "admin"}, {"age": {"gte": 40}}]}
Update operators: $set, $unset, $inc, $push, $pull, $addToSet. Plus
aggregate(_count=True, _sum=["amt"], _avg=["amt"], _min=[...], _max=[...]) and
group_by("category", _count=True, _sum=["amt"]).
Transactions
with db.transaction(): # nestable via SAVEPOINTs; rolls back on exception
orders.create({...})
inventory.update({"_id": sku}, {"$inc": {"stock": -1}})
Change feed — see what Node wrote (and vice-versa)
Opt in with changefeed=True; writes append to _monlite_changes in the exact format the TS side
reads (upsert/delete ops, the <padded-ms>:<nodeId>:<padded-seq> version string):
db = create_db("shared.db", changefeed=True)
last = 0
while True:
for ch in db.changes(since=last): # ordered; includes Node's writes
handle(ch["coll"], ch["doc_id"], ch["op"])
last = ch["seq"]
time.sleep(0.2)
kv — cache, locks, pub/sub, sorted sets (Redis's local role)
c = kv(db)
c.set("k", {"v": 1}, ttl=60_000); c.incr("hits")
c.set_nx("lock:job", 1, ttl=5_000) # atomic set-if-absent
with c.with_lock("report", ttl_ms=10_000): # ergonomic distributed lock
build_report()
c.subscribe("jobs", lambda m: print("got", m))
c.publish("jobs", {"id": 7}) # same-process now; c.poll() drains other writers
c.zadd("board", 100, "ada"); c.zincrby("board", 5, "bo")
c.zrange("board", 0, -1, rev=True) # leaderboard; zrank/zscore/zrange_by_score too
Durable queue
from monlite import create_queue
q = create_queue(db)
q.add("email", {"to": "a@b.c"}, priority=5, max_attempts=3) # retries + backoff + dedupe (job_id)
q.process("email", lambda payload: send(payload)) # claim+run loop (multi-process safe)
A Node @monlite/queue worker and this one share _jobs — enqueue in Python, process in Node, or
the reverse.
Cron
from monlite import create_cron, next_cron_run
cron = create_cron(db)
cron.schedule("digest", "0 9 * * *", send_digest, tz="Europe/Istanbul", jitter=30_000)
cron.tick() # fire due schedules (call on your own loop; multi-process safe via atomic claim)
next_cron_run("*/15 * * * *") # -> datetime
Full-text search (FTS5)
from monlite import fts
idx = fts(db, "posts", fields=["title", "body"]) # builds the FTS5 index + keeps it current
posts = db.collection("posts")
posts.create({"title": "SQLite is great", "body": "embedded and fast"})
idx.search("sqlite", limit=10) # ranked documents (interop-compatible with Node)
Cross-language interop
Each runtime is a complete, independent library; the shared-file interop is a bonus you opt into. The interop test suite round-trips documents, the change feed, sorted sets, and the queue between Node and Python over one file. See the file format spec for the conventions both sides follow.
Optional extras
The whole stack above is pure standard-library sqlite3. Native extras mirror the TypeScript
packages and install separately:
pip install "monlite[vector]" # semantic search via sqlite-vec
pip install "monlite[postgres]" # sync to PostgreSQL
pip install "monlite[mongo]" # sync to MongoDB
Status
Documents (with transactions, aggregation, and the change feed), kv (cache, locks, pub/sub,
sorted sets), the durable queue, cron, and FTS5 are implemented and covered by tests — including
a cross-runtime interop suite. The [vector] extra and sync adapters are next. The
file format is the contract every part shares.
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file monlite-0.1.0.tar.gz.
File metadata
- Download URL: monlite-0.1.0.tar.gz
- Upload date:
- Size: 44.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e1e5fa47180ea80c2d465afe6933a4330eea163a25b919aabc5f7be1f3e91b94
|
|
| MD5 |
cbc40801c0bc486d7f69da58f1cd101b
|
|
| BLAKE2b-256 |
49e81d25309c7d9264d58cc6375e4d7bfa13632cb4a1838f966554aeeb63ced5
|
File details
Details for the file monlite-0.1.0-py3-none-any.whl.
File metadata
- Download URL: monlite-0.1.0-py3-none-any.whl
- Upload date:
- Size: 33.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.9.6
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f3f9b81938d6e406bb32abbe48be690af1c6eb890d1202d9d3e25f092562f36d
|
|
| MD5 |
7744893e8c0b3dce48e1004d9ac1aadf
|
|
| BLAKE2b-256 |
0c904772e975a963394a030800f669d6ac432632b6999115493efae6b2103777
|