DRAFTThis page is not published. Only visible in development mode.

Python

The Python binding is an early prototype, version 0.0.1. It is a PyO3 module that embeds the engine inside the Python process - the same shape as Rust (Embedded), not a remote client - and it was written against an engine API that has since been replaced. This page documents what the prototype is, why you should not build on it yet, and how to use ReifyDB from Python today while it waits for its rewrite.

What exists today

The package lives at pkg/python/reifydb in the engine repository and is built with maturin (PyO3, abi3, Python 3.10+). It exposes exactly one class with one method:

python
from reifydb import Embedded

db = Embedded()               # in-memory engine, in-process
results = db.tx('FROM app::users')

Embedded() starts a blocking in-memory engine as the root identity; there is no persistence option and no way to run as another identity. tx(rql) executes RQL and returns a list with one plain dict per statement result, tagged by kind: a query result is {'type': 'Query', 'headers': [...], 'rows': [...]}, and schema and insert statements return CreateNamespace/CreateTable/InsertIntoTable dicts naming what they touched. Every cell in rows is a string - the prototype formats values on the way out rather than mapping engine types to Python types. There is no query/command split, no parameters, no subscriptions, and no error surface beyond the exception PyO3 raises.

How it was meant to be used

The repository ships one example, a hello world that pretty-prints a query result with tabulate. It is reproduced here as a record of intent - note that even its RQL predates the current syntax:

python
from reifydb import Embedded
from tabulate import tabulate

db = Embedded()
r = db.tx('map 1, 1 + 4')

print(tabulate(r[0]['rows'], headers=r[0]['headers']))

The development notes describe the standard maturin workflow - maturin build, pip install . - but that workflow does not currently produce a working module, for the reasons below. The package is not published; there is no pip install reifydb from PyPI.

Current status

Stale prototype - do not build on it
The binding was written against engine APIs that no longer exist. Its Rust source calls ReifyDB::embedded_blocking() and reifydb::variant::Embedded, both long gone from the crate (the current embedded surface is embedded::memory() and sessions, see Rust (Embedded)). The crate is excluded from the engine workspace, its dependency on the engine is commented out, and its entire implementation sits behind an include-python-workspace feature flag - it does not compile against the current engine. The API will change completely when it is brought up to date.

Concretely, as of engine 0.8.1: embedded only, no remote client; in-memory only, no persistence; root identity only; results are stringified, not typed; and the shipped type stubs do not even match the module (they declare a ReifyDB class with query(), while the module exposes Embedded with tx()). Treat the whole package as a preview of intent, not a foundation.

Using ReifyDB from Python today

Until the binding is rewritten, the practical route is to run the server and speak the HTTP wire protocol directly - it is plain JSON over POST, so the standard requests package is all you need. This is not an official SDK, just the protocol every client uses underneath. Statements go to /v1/query (reads) and /v1/command (writes) on the application port 8090; ?format=json asks for row-shaped JSON, one list of row dicts per result frame:

python
import requests

resp = requests.post(
    'http://localhost:8090/v1/query',
    params={'format': 'json'},
    json={'rql': 'FROM app::users FILTER age >= $min', 'params': {
        # Parameters travel as typed pairs; the value is always a string.
        'min': {'type': 'Int4', 'value': '18'},
    }},
)
resp.raise_for_status()

frames = resp.json()          # one entry per result frame
for row in frames[0]:         # each row is a plain dict
    print(row['id'], row['name'])

Positional parameters ($1, $2, ...) are a JSON array of the same typed pairs, and omitting params means none. To run as a real identity, POST the login to /v1/authenticate and send the returned token as an Authorization: Bearer <token> header on every request. Admin statements need the loopback-only admin listener on port 9090 - ports and the login flow are covered on Connect, and the full request and response encodings on Wire Formats. HTTP has no subscriptions; live data needs the WebSocket protocol.

Where next
The clients overview maps every way into the engine and each client's maturity. Connect gets a server running to point Python at, and Wire Formats is the reference if you go further down the protocol route.