Python SDK
The widest of the three clients. Sync and async, typed namespaces for every query surface, and the only one that retries transient failures for you.
Install
Python 3.9 or newer. The client uses httpx, and will negotiate HTTP/2 when the extra is present.
pip install originchainConnect
The standard bootstrap reads three environment variables - OC_BASE_URL, OC_BEARER and OC_TENANT - and raises if any is missing, rather than failing later on the first call.
from originchain import OriginChain
db = OriginChain.from_env()
print(db.health())Pass them explicitly when the environment is not yours to set, in tests for instance:
db = OriginChain(
base_url="https://t-abc.your-region.db.originchain.ai",
bearer="oc_live_...",
tenant="t-abc",
timeout=30.0,
max_retries=3,
)There is an async client with the same surface. Everything on this page works on it with await, and it closes with await db.aclose().
from originchain import AsyncOriginChain
db = AsyncOriginChain.from_env()
rows = await db.sql("SELECT 1")
await db.aclose()The namespaces
The client is organised by surface. Each namespace hangs off the client instance:
| Namespace | What is on it |
|---|---|
| db.schemas | list(), get(), register() |
| db.rows | get(), put(), put_batch() |
| db.sql | callable, plus query(), execute() and the materialized-view calls |
| db.vector | put(), topk(), delete(), delete_bulk(), centroid install and training |
| db.fts | index(), search(), install_synonyms(), install_stopwords() |
| db.graph | neighbours, BFS, shortest path, Dijkstra, and the graph algorithms |
| db.admin | per-tenant replication configuration |
db.sql is a callable namespace. db.sql("SELECT ...") and db.sql.query("SELECT ...") both work and hit the same endpoint, so older code keeps running while new code can reach the typed calls next to it.
Register a schema and write rows
A schema is TOML, and it is the same declaration every surface reads - see the schema reference.
db.schemas.register(open("products.toml").read())
db.schemas.list()
db.rows.put("shop.products", {
"id": "sku-1",
"name": "Aeron chair",
"price": 1195,
})
# Batched writes are chunked, and each chunk carries its own
# derived idempotency key, so a partial retry does not duplicate.
db.rows.put_batch("shop.products", rows)Query
SQL
resp = db.sql.query(
"SELECT name, price FROM shop.products WHERE price > 500 ORDER BY price DESC"
)
for r in resp.rows:
print(r["name"], r["price"])
one = db.sql_one("SELECT count(*) AS n FROM shop.products")Full-text
db.fts.index("shop.products", "name", pk="sku-1", text="Aeron chair")
hits = db.fts.search("shop.products", "name", q="chair", limit=10)Vector
db.vector.put("shop.products", pk="sku-1", vector=embedding)
hits = db.vector.topk("shop.products", vector=query_vec, k=10)Graph
The five traversals plus the algorithm calls. Which algorithms your instance answers is covered in the graph reference.
db.graph.neighbors("shop", rel="bought_with", pk="sku-1")
db.graph.bfs("shop", rel="bought_with", pk="sku-1", depth=3)
db.graph.pagerank("shop", rel="bought_with")
db.graph.louvain("shop", rel="bought_with")Natural language
answer = db.ask("which products sold best last week?", schemas=["shop"])Errors
Every failure is a typed exception, so you can catch the one case you can do something about:
| Exception | Raised when |
|---|---|
| OCAuthError | the token is missing, wrong, or lacks the role for this call |
| OCValidationError | the request was malformed - a bad schema, an unknown column |
| OCNotFoundError | the schema, table or row does not exist |
| OCPaymentRequiredError | the call needs an add-on the account does not have |
| OCRateLimitedError | the tenant is over its request budget |
| OCServerError | the engine failed - retried already, if retries are on |
| OCReplicationDegraded | a warning, not an exception: the read was served while a replica was catching up |
All of them subclass OCError, so a single catch still works.
from originchain import OCRateLimitedError, OCError
try:
db.sql("SELECT 1")
except OCRateLimitedError:
back_off()
except OCError as e:
log.exception(e)Retries and idempotency
This client retries 429, 500, 502, 503 and 504 up to max_retries times. Mutating requests carry a generated Idempotency-Key, which the engine caches server-side, so a retried write lands once.
Pass a stable idempotency_key yourself when the retry has to survive a process restart - a job runner picking the same task up again, for instance. Batched writes derive one key per chunk from the key you give, so partial progress is preserved.
Source
pip install originchain · originchain-ai/originchain-python · the HTTP API underneath