marsdb (Python)
Python bindings for MarsDB, an embeddable property-graph database with an openCypher query subset: single file on disk (or fully in-memory), no server, ACID transactions. In-process via PyO3 — no C ABI, no sockets, queries run on the calling thread.
Not published to PyPI yet — build from the repo with maturin:
cd marsdb-python
maturin develop --release
Quickstart
import marsdb
db = marsdb.Database.in_memory() # or marsdb.Database.open("graph.db")
db.execute("CREATE (a:Person {name: 'Alice'})-[:KNOWS {since: 2001}]->(b:Person {name: 'Bob'})")
for row in db.execute("MATCH (a:Person)-[:KNOWS]->(b) RETURN a.name, b.name"):
print(row["a.name"], "knows", row["b.name"])
execute runs one Cypher statement and returns a list of dicts, one
per result row, keyed by column name.
Parameterized queries
execute takes an optional params dict resolving $name placeholders
— no string interpolation, no escaping bugs:
db.execute(
"MATCH (p:Person {name: $name}) RETURN p.age",
{"name": "O'Hara"},
)
Values may be None/bool/int/float/str, or nested list/dict
of those. Ints keep their full 64-bit range; an int outside i64 raises
instead of truncating. Map-valued params work ($m.city).
Errors
Everything raised derives from marsdb.Error; subclasses expose the
engine's own taxonomy so programs catch selectively instead of
string-matching:
| Exception | Raised for |
|---|---|
ProgrammingError |
syntax/semantic errors, unbound variables, missing $params, stray COMMIT |
DataError |
type errors, integer overflow, unstorable parameter values |
IntegrityError |
unique-index violations, deleting a connected node without DETACH |
OperationalError |
timeout, cancellation, max_rows exceeded, storage failures |
Execution bounds
db.execute("MATCH (n) RETURN n", max_rows=100_000, timeout_ms=5_000)
Both are checked during evaluation — a runaway query raises
OperationalError at the bound instead of materializing an unbounded
result first, so it can't OOM the process.
Streaming (bulk export)
db.execute_streaming(
"MATCH (n:Person) RETURN n.name AS name",
lambda row: writer.writerow(row), # return False to stop early
)
Rows are pushed one at a time — bounded memory no matter how many rows
match. Accepts exactly the streamable shape (one plain MATCH ... RETURN, SKIP/LIMIT fine) and raises ProgrammingError for ORDER BY/aggregation/DISTINCT/WITH — those must see all rows before
emitting any, so streaming them would be pretend; use execute.
Arrow (pyarrow / polars / pandas / DuckDB)
query_arrow returns the result as an Arrow stream — an object
implementing the Arrow PyCapsule protocol, accepted directly by any
Arrow consumer with zero per-value conversion:
import pyarrow as pa
table = pa.table(db.query_arrow("MATCH (n:Person) RETURN n.name AS name, n.age AS age"))
df = table.to_pandas() # or polars.from_arrow(table), duckdb.sql(...)
Column types are inferred strictly, per column over the whole result:
int64 (full 64-bit, exact), float64, string, bool, date32,
month-day-nano interval for durations, ISO-8601 text for other
temporals, lists of one element type. A column mixing ints and floats
raises DataError — silent promotion to float would corrupt integers
beyond 2⁵³; cast in the query (toFloat/toInteger) instead. So do
node/relationship/map/path columns: project scalar properties.
The stream is single-use (hand it to one consumer); batch_rows
(default 8192) sets rows per record batch, and .stats carries the
statement's write counters. pyarrow itself is not a dependency of
this package — anything speaking the protocol works.
Value mapping
| Cypher | Python |
|---|---|
| integer | int (full 64-bit, no precision loss) |
| float / string / boolean / null | float / str / bool / None |
| list / map | list / dict |
| node | {"id": ..., "labels": [...], "props": {...}} |
| relationship | {"id": ..., "label": ..., "src": ..., "dst": ..., "props": {...}} |
| date / duration | ISO-8601 str |
Transactions
BEGIN / COMMIT / ROLLBACK are statements (BEGIN TRANSACTION
also accepted). One session per Database handle; reads inside a
transaction see its own uncommitted writes; a statement that fails at
execution time rolls the whole transaction back.
db.execute("BEGIN")
db.execute("CREATE (:Account {id: 1, balance: 100})")
db.execute("CREATE (:Account {id: 2, balance: 0})")
db.execute("COMMIT") # or ROLLBACK to discard both
Schema introspection
db.execute("CALL db.labels()") # [{'label': 'Person', 'count': 2}]
db.execute("CALL db.relationshipTypes()") # [{'relationshipType': 'KNOWS', 'count': 1}]
db.execute("CALL db.propertyKeys()") # [{'propertyKey': 'name'}, ...]
db.execute("CALL db.indexes()") # [{'label': ..., 'property': ..., 'unique': ...}]
Examples
examples/commit_graph.py— build a graph of a git repo's history (commits, files,TOUCHESedges).examples/visualize_commit_graph.py— render it as a PNG.
Tests
maturin develop && python -m unittest discover tests
Cypher coverage, benchmarks, and the full manual live in the main repository.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
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 marsdb-0.9.1.tar.gz.
File metadata
- Download URL: marsdb-0.9.1.tar.gz
- Upload date:
- Size: 613.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fb0ecfe80c39286ec2c35d96f93346e51d3c8aa5f89eb2da7567ae9d54627c3d
|
|
| MD5 |
88721b64be003cad65716b232c6ae2ea
|
|
| BLAKE2b-256 |
cddbc87cb2798c8fb394e358bae16c45600921cf16b10e72fa21b0ea43b58e8f
|
File details
Details for the file marsdb-0.9.1-cp314-cp314-macosx_11_0_arm64.whl.
File metadata
- Download URL: marsdb-0.9.1-cp314-cp314-macosx_11_0_arm64.whl
- Upload date:
- Size: 2.6 MB
- Tags: CPython 3.14, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ffef7a454aabd6dde5dc68b26f286208952f88fbe44adb0336539e6f485da068
|
|
| MD5 |
6bc47bdae11f5bd68633878a35c216e9
|
|
| BLAKE2b-256 |
a6497ce5bf577b782a32117689086a631b4d91b40c484992151553a6bcf26284
|
File details
Details for the file marsdb-0.9.1-cp314-cp314-macosx_10_12_x86_64.whl.
File metadata
- Download URL: marsdb-0.9.1-cp314-cp314-macosx_10_12_x86_64.whl
- Upload date:
- Size: 2.7 MB
- Tags: CPython 3.14, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cf9b41eebfaa44dcd75b1c859365c6459b2a1eee06dac79274b979496c444d6c
|
|
| MD5 |
552bf8c28d14eefa1d522e609c3021fd
|
|
| BLAKE2b-256 |
bdd9f0d6fa86133cf00c60730799ead60fbe8b55206786169f5120cf7db8e8ae
|
File details
Details for the file marsdb-0.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: marsdb-0.9.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 3.0 MB
- Tags: CPython 3.9, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
12f603ec785a2912aae48f63468c8f212d6cb7224738668bad7ab4bd90c11d7c
|
|
| MD5 |
e2d5fba0363cfc8068bd2744693b043f
|
|
| BLAKE2b-256 |
6b4c32db79762d62ce565fc4dfbe33d353e226bf62c75c7f02266f87b27a6ae8
|