Python SDK

Async and sync Python client for InferaDB.

Coming soon. The Python SDK is under active development. The API surface shown here is based on the Rust SDK and may change before release.

Async and sync clients for InferaDB’s authorization APIs. Requires Python 3.10+.

Installation

pip install inferadb

Authentication

Three authentication methods:

Method Use Case Security
Client Credentials (Ed25519 JWT) Service-to-service High
Bearer Token User sessions, OAuth Medium
API Key Testing, simple integrations Basic
from inferadb import InferaDB, Ed25519PrivateKey

client = InferaDB(
    url="https://engine.inferadb.com",
    credentials={
        "client_id": "my-client",
        "private_key": Ed25519PrivateKey.from_pem_file("client.pem"),
        "certificate_id": "cert-id",
    },
)

Bearer Token

import os
from inferadb import InferaDB

client = InferaDB(
    url="https://engine.inferadb.com",
    token=os.environ["INFERADB_TOKEN"],
)

API Key

import os
from inferadb import InferaDB

client = InferaDB(
    url="https://engine.inferadb.com",
    api_key=os.environ["INFERADB_API_KEY"],
)

Permission Checks

vault = client.organization("my-org").vault("production")

allowed = await vault.check("user:alice", "can_edit", "document:readme")

With ABAC Context

allowed = await vault.check(
    "user:alice", "can_view", "document:readme",
    context={"ip_address": "10.0.0.1"},
)

Require — Raises on Deny

# Raises AccessDeniedError if permission is denied
await vault.require("user:alice", "can_edit", "document:readme")

With Consistency Token

allowed = await vault.check(
    "user:alice", "can_view", "document:readme",
    at_least_as_fresh=revision_token,
)

Batch Check

results = await vault.check_batch([
    ("user:alice", "can_edit", "document:readme"),
    ("user:bob", "can_view", "document:readme"),
])
assert results.all_allowed()

Sync API

from inferadb import InferaDBSync

client = InferaDBSync(url="https://engine.inferadb.com", token="...")
vault = client.organization("my-org").vault("production")

allowed = vault.check("user:alice", "can_edit", "document:readme")

Relationships

Write

# Returns a revision token
token = await vault.relationships.write(
    resource="document:readme",
    relation="editor",
    subject="user:alice",
)

Batch Write

await vault.relationships.write_batch([
    {"resource": "document:readme", "relation": "editor", "subject": "user:alice"},
    {"resource": "document:readme", "relation": "viewer", "subject": "user:bob"},
])

List

rels = await vault.relationships.list(resource="document:readme")

Delete

await vault.relationships.delete_where(
    resource="document:readme",
    relation="viewer",
    subject="user:bob",
)

Lookups

# What resources can Alice view?
resources = await vault.resources.accessible_by(
    "user:alice",
    permission="can_view",
    resource_type="document",
)

# Who can edit this document?
subjects = await vault.subjects.with_permission(
    "can_edit",
    resource="document:readme",
)

Testing

MockClient (Fastest)

Stub specific check results. Call assert_expectations() to verify all stubs were hit.

from inferadb.testing import MockClient

client = (
    MockClient()
    .on_check("user:alice", "can_edit", "document:readme").allow()
    .on_check("user:bob", "can_edit", "document:readme").deny()
    .on_check_any_subject("can_view", "document:readme").allow()
    .default_deny()
)

client.assert_expectations()

InMemoryClient (Full Policy Evaluation)

Evaluates policies locally with no I/O. Synchronous construction.

from inferadb.testing import InMemoryClient

client = InMemoryClient.with_schema_and_data(
    schema="""
    type document {
        relation viewer
        relation editor
        relation can_view = viewer | editor
    }
    """,
    data=[
        ("document:readme", "editor", "user:alice"),
        ("document:readme", "viewer", "user:bob"),
    ],
)

TestVault (Real Instance)

Runs against a live InferaDB instance. Auto-cleans up on GC; call vault.preserve() to keep data for debugging.

from inferadb.testing import TestVault

vault = await TestVault.create(org, schema=schema_ipl)

pytest Integration

import pytest
from inferadb.testing import InMemoryClient

@pytest.fixture
def authz():
    return InMemoryClient.with_schema_and_data(
        schema="...",
        data=[("document:readme", "editor", "user:alice")],
    )

async def test_alice_can_edit(authz):
    vault = authz.organization("test").vault("test")
    assert await vault.check("user:alice", "can_edit", "document:readme")

Requires asyncio_mode = "auto" in pyproject.toml.

Error Handling

from inferadb import AccessDeniedError, InferaDBError

try:
    await vault.require("user:alice", "can_edit", "document:readme")
except AccessDeniedError:
    # permission denied
    pass
except InferaDBError as e:
    if e.is_retriable:
        # retry after e.retry_after seconds
        pass
    print(e.kind, e.request_id)

ErrorKind values: "unauthorized", "forbidden", "not_found", "rate_limited", "schema_violation", "unavailable", "timeout", "invalid_argument".

Framework Integrations

FastAPI Dependency

from fastapi import Depends, Request
from inferadb.fastapi import require_permission

@app.get("/documents/{doc_id}")
async def get_document(
    doc_id: str,
    request: Request,
    _=Depends(require_permission(
        vault,
        subject=lambda req: f"user:{req.state.user_id}",
        permission="can_view",
    )),
):
    return {"id": doc_id}

Resource is resolved from path parameters automatically. Override with an explicit resource callback:

require_permission(
    vault,
    subject=lambda req: f"user:{req.state.user_id}",
    resource=lambda req: f"document:{req.path_params['doc_id']}",
    permission="can_view",
)

Django Decorator

from inferadb.django import require_permission

@require_permission(
    vault,
    subject=lambda request: f"user:{request.user.id}",
    resource=lambda request, pk: f"document:{pk}",
    permission="can_edit",
)
def update_document(request, pk):
    # only reached if authorized
    pass