Skip to main content
Pre-release

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

OriginChainDB for Python

The originchain package provides synchronous and asynchronous clients for OriginChainDB, with typed namespaces for SQL, rows, vector search, full-text search and graph operations.

Documentation | Changelog | Issues | Other languages

Installation

Requires Python 3.9 or later. Install the current GitHub preview:

python -m pip install "https://github.com/originchaindb/originchain-python/releases/download/v0.10.0-rc.5/originchain-0.10.0rc5-py3-none-any.whl"

Version 0.10.0rc5 is a prerelease. pip install originchain may select an older PyPI version with a smaller async API. Async support and HTTP/2 dependencies are included; no extra is required. Checksums are on the release page.

Your first query

Set the connection details for one database in your environment:

Variable Value
OC_BASE_URL Full database HTTPS endpoint
OC_TENANT Tenant ID from the same connection details
OC_BEARER Instance bearer token

Save this as query.py and run python query.py. It needs no tables or sample data.

from originchain import OriginChain

with OriginChain.from_env() as db:
    result = db.sql.query(
        "SELECT $1 AS message",
        params=["Hello from OriginChainDB"],
    )
    for row in result.rows:
        print(row["message"])

Reuse a client across requests to reuse its HTTP connections. The context manager closes it; otherwise call close() when finished.

If your database requires user identity, provide both values alongside the instance bearer:

import os
from originchain import OriginChain

with OriginChain.from_env(
    db_user=os.environ["OC_DB_USER"],
    db_key=os.environ["OC_DB_KEY"],
) as db:
    print(db.sql_one("SELECT $1 AS value", [7]))

The two credentials add database-user headers; they do not replace the bearer token. Omit both for a bearer-only connection. from_env() reads the three connection variables above; pass optional settings as keyword arguments.

Async applications

AsyncOriginChain has the same operation namespaces. Await network calls and use async with to close the client:

import asyncio
from originchain import AsyncOriginChain

async def main():
    async with AsyncOriginChain.from_env() as db:
        result = await db.sql.query("SELECT $1 AS message", ["Hello from async Python"])
        print(result.rows)

asyncio.run(main())

For an overall deadline, wrap a call in asyncio.wait_for. Cancellation interrupts local work and retry waits; a write may already have reached the server.

SQL and rows

The examples below assume quickstart.products from the database quickstart. Each block reuses an open db client.

result = db.sql.query(
    "SELECT id, name, price_cents FROM quickstart.products "
    "WHERE price_cents < $1 LIMIT 10",
    params=[2000],
)
for row in result.rows:
    print(row["id"], row["name"])

Parameters are positional: lists bind $1, $2 and so on. Dictionaries are rejected. Bind values instead of inserting them into SQL strings. Keep table and column names under application control.

Use db.sql.execute(...) for execution results and db.sql_one(...) for one row or None. The older callable db.sql(...) remains available and returns a tagged result. Server-reported write counts can be zero or None; an absent count is unknown. rows_buffered is separate from committed execution.

SqlDelete.pk is None when the server does not return a single deleted primary key, including bulk DELETE results. Use the server-reported rows_affected count to inspect execution.

SqlResult.columns records projection order. Row dictionaries keep the keys the server returns: a GROUP BY key that is absent from the SELECT list need not appear in the row. The SDK does not reconstruct hidden keys or strip extra keys returned by older servers. Materialized-view rows follow the same rule.

SQL cell values

SqlResult.column_types and SqlSelect.column_types expose the server's optional output-name-to-type map, for example {"amount": "numeric", "created_at": "timestamp"}. It can be sparse or absent; it is not a complete schema.

  • Decimal/numeric values remain strings, preserving scale and precision, including "NaN", "Infinity" and "-Infinity".
  • SQL timestamp text retains every returned fractional digit. Row reads can return an integer in epoch milliseconds for legacy columns or ISO-8601 text such as "2024-02-29T12:34:56.123456Z" for columns with microsecond support. Check the value's type before doing timestamp arithmetic.
  • On writes through row JSON or SQL params, a timestamp integer means epoch milliseconds; ISO-8601 text can carry microseconds when the server/column supports them. Do not pass epoch microseconds as an integer. For newer timestamp columns, bind a number as a JSON parameter rather than writing an integer literal into SQL text.
  • Date/time infinity and interval values remain exact strings. An interval such as "1 year 2 mons 3 days 04:05:06" is not collapsed into a timedelta; legacy row interval values can still be integer milliseconds.
  • For an SQL column explicitly marked double precision, real, float4 or float8, "NaN", "Infinity" and "-Infinity" become Python floats. Other values are unchanged. Without that metadata, the SDK preserves strings; rows.get() has no type envelope and preserves its JSON values too.

These rules preserve values across engine versions; they do not enable server features. Current compatibility acceptance confirms projected GROUP BY rows and microsecond SQL literals. The tested engine still stores newly declared timestamp/interval table columns at millisecond precision and rejects the special-value casts, so stored microsecond and special-value acceptance remains pending.

For row APIs and batches:

db.rows.put("quickstart.products", {
    "id": "product-001", "name": "Trail mug", "price_cents": 1500,
})

accepted = db.rows.put_batch(
    "quickstart.products",
    ({"id": f"product-{i}", "name": f"Item {i}", "price_cents": 1000}
     for i in range(10, 30)),
    chunk=10,
    idempotency_key="catalog-import-001",
)
print(accepted)

Batches are sent sequentially. Async batches also accept async iterables. Each chunk receives a distinct key derived from the base key. Failure or cancellation stops later chunks; earlier chunks may already be durable. Before replaying a batch, check the server outcome and keep the same base key, ordering and chunk size. Deduplication depends on the endpoint and its retention window.

The SDK accepts embeddings supplied by your application. Use a table configured for the chosen vector dimensions and metric:

db.vector.put("quickstart.products", "product-001", [0.1, 0.2, 0.3])
hits = db.vector.topk("quickstart.products", [0.1, 0.2, 0.3], k=5, metric="cosine")
for hit in hits:
    print(hit.vec_id, hit.score)

Prepare the field using the full-text guide, then index and search it:

db.fts.index("quickstart.products", "name", "product-001", "Trail mug")
result = db.fts.search("quickstart.products", "name", "trail", mode="bm25", k=5)
for hit in result.hits:
    print(hit.doc_id, hit.score)

API namespaces

Namespace Operations Reference
db.schemas Register and inspect table schemas Schemas
db.rows Read, write and batch rows Insert data
db.sql Parameterized queries and execution; materialized views SQL
db.vector Vector storage, search, deletion and index controls Vector search
db.fts Indexing, search and text-analysis controls Full-text search
db.graph Traversals, shortest-path costs and graph algorithms Graphs
db.admin Privileged engine configuration HTTP API

These namespaces exist on both clients. Operations require the corresponding engine feature and permissions. The client source and typed namespaces define the Python signatures. Graph relations must be registered before traversal; Dijkstra uses directed node-pair weights and returns a nullable cost rather than a path.

db.ask(...) requires Ask to be enabled for the database. Successful Ask execution is not part of this preview's live verification. Optional engine features and administrative mutations have different capability and permission requirements.

Timeouts and retries

Pass these options to either constructor or from_env():

Option Default Meaning
timeout 30.0 seconds HTTPX network-phase timeout
max_retries 3 Additional attempts for eligible requests; 0 disables retries
max_retry_time 30.0 seconds Budget for scheduling retry delays and attempts
verify True TLS certificate verification; accepts a CA bundle path
diagnostics False Report bounded request metadata to your database

GET, HEAD and OPTIONS can retry automatically. SQL and writes do not. To retry a read-only SQL operation, opt in on that call:

with OriginChain.from_env(max_retries=2, max_retry_time=15) as db:
    row = db.sql_one("SELECT $1 AS value", [7], retry_safe=True)

Set retry_safe=True only when repeating the operation is safe. An idempotency key alone is insufficient. Eligible calls retry transport failures and HTTP 429, 500, 502, 503 and 504, using jitter and Retry-After. The retry budget does not interrupt a request already in flight; use an application deadline when needed.

Errors and diagnostics

from originchain import OCError

try:
    result = db.sql.query("SELECT $1 AS value", [7])
except OCError as error:
    print(error.status, error.request_id, error.logical_request_id)
    raise

HTTP failures use OCError subclasses. Transport failures are wrapped in OCError, with the underlying HTTPX exception available as error.__cause__. OCReplicationDegraded is a warning about replication acknowledgement, not an OCError. Include the request ID in support reports and keep credentials and query data out of logs.

Diagnostics are opt-in and report request metadata to your own engine, excluding SQL text, parameters and row contents. Closing the client flushes pending reports.

Query metrics

with OriginChain.from_env() as db:
    metrics = db.query_metrics(minutes=60, bucket_seconds=60)
    for bucket in metrics["buckets"]:
        duration = bucket["observed_seconds"]
        rate = bucket["calls"] / duration if duration > 0 else None
        print(bucket["at"], rate, bucket["mean_latency_ms"])

Use service or query-administrator credentials without database-user impersonation headers. Supported (minutes, bucket_seconds) pairs are (60, 60), (1440, 600) and (10080, 3600). Metrics are process-local and reset on restart. Idle latency is None; timestamps are Unix milliseconds. The response uses typed dictionaries and preserves integer counts.

Compatibility and development

CI covers Python 3.9, 3.12 and 3.14 on Linux, plus Python 3.12 on Windows and macOS. The release page contains package checksums and the scope of live database verification. The 0.x API can change before 1.0.

python -m venv .venv
# Activate .venv using your shell's activation command.
python -m pip install -e ".[dev]" build twine
python -m pytest -q
python -m ruff check originchain tests
python -m build
python -m twine check dist/*

Open an issue with the SDK and Python versions, request ID and a small reproduction with credentials removed.

License

MIT.

Metadata

Release files for originchain 0.10.0rc5

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

Source distribution (sdist)

Source distribution for originchain 0.10.0rc5
File Size Uploaded Provenance
originchain-0.10.0rc5.tar.gz 98.6 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for originchain 0.10.0rc5
File Interpreter ABI Platform
originchain-0.10.0rc5-py3-none-any.whl Python 3 none any Details

Total release size: 161.3 kB

Release files / originchain-0.10.0rc5.tar.gz

Download URL originchain-0.10.0rc5.tar.gz
Size 98.6 kB
Tags Source
SHA-256 checksum
How to use checksums
7bb229f037c78d8e51696c867cb8f4ddeb61cc4bc0b9ccb3604ff22bedd0a2a7
BLAKE2b-256 checksum
How to use checksums
71e21a28f5f1e06ee81f000573d2b74d26340249c023743540bb45e1e5e27f64
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.10

Release files / originchain-0.10.0rc5-py3-none-any.whl

Download URL originchain-0.10.0rc5-py3-none-any.whl
Size 62.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2939a3e955fbb070f63a2ba30f5603122e56239568b2107cde58eb1621f987fd
BLAKE2b-256 checksum
How to use checksums
5ca8825a9b1d3ffb03b22c3b32cfd2ba0360225eb75ba7a3dee0a606afa5d04f
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.10

Security for originchain 0.10.0rc5

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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