Metadata-Version: 2.4
Name: rafflesia-sdk
Version: 0.2.1
Summary: Rafflesia public API Python SDK (generated from the OpenAPI contract)
License: MIT
Project-URL: Homepage, https://rafflesia.ai
Requires-Python: >=3.11
Description-Content-Type: text/markdown
Requires-Dist: httpx
Requires-Dist: pydantic>=2
Requires-Dist: backoff
Requires-Dist: typing-extensions
Dynamic: requires-python

# Rafflesia Python SDK

A typed Python client for the Rafflesia public API, generated from the server's
OpenAPI contract by the `oagen` product generator.

```bash
pip install rafflesia-sdk
```

```python
from rafflesia import Rafflesia

client = Rafflesia(api_key="...")  # or RAFFLESIA_API_KEY env var
databases = client.homology.databases.list()
releases = client.homology.databases.releases.list("tomato")
result = client.homology(
    database="tomato",
    query={
        "kind": "protein_sequence",
        "sequence": "MTEYKLVVVGAGGVGKSALTIQLIQNHFVDEYDPTIEDSYRKQ",
    },
)
batch = client.homology_many(
    database_release_id=releases.data[0].id,
    queries=[
        {"kind": "protein_sequence", "sequence": "MTEYK"},
        {"kind": "protein_sequence", "sequence": "GAGGVGKS"},
    ],
    include=[],
    limit=100,
)
```

Async:

```python
from rafflesia import AsyncRafflesia

async with AsyncRafflesia(api_key="...") as client:
    result = await client.homology(
        database="tomato",
        query={"kind": "protein_sequence", "sequence": "MTEYK"},
    )
    batch = await client.homology_many(
        database="tomato",
        queries=[
            {"kind": "protein_sequence", "sequence": "MTEYK"},
            {"kind": "protein_sequence", "sequence": "GAGGVGKS"},
        ],
    )
```

## Runs

`run()` and `submit()` create the same durable request. `run()` waits for its
result; `submit()` returns a handle immediately. Once accepted, `request_id` is
the only value needed to recover, inspect, fetch, or cancel the run.

```python
result = client.run("meta-ai/esm2/650m", {"sequences": ["MTEYK"]})

handle = client.submit(
    "meta-ai/esm2/650m",
    {"sequences": ["MTEYK"]},
    start_timeout=30,
)
status = client.status(handle.request_id, with_logs=True)
result = client.result(handle.request_id)
client.cancel(handle.request_id)

# Recover the same durable handle in another process.
handle = client.get_handle(handle.request_id)
```

A local wait timeout does not cancel accepted work. Raw webhook URLs are not
accepted; register a webhook endpoint and pass its ID when submitting.

File-bearing model fields use managed URLs. The high-level storage helpers use
a one-shot upload through 10 MiB, then switch to resumable direct-to-bucket
multipart transfer without retaining the complete file in memory:

```python
url = client.storage.upload_file(
    "structure.cif",
    content_type="chemical/x-mmcif",
    lifecycle={
        "expires_in": "30d",
        "initial_acl": {
            "default": "forbid",
            "rules": [{"user": "user_123", "decision": "allow"}],
        },
    },
)
raw_url = client.storage.upload(b"bytes", "application/octet-stream")
image_url = client.storage.upload_image(image, file_name="preview.jpg")
```

`AsyncRafflesia` exposes the same three helpers as coroutines. The generated
one-request operation remains available as `storage.upload_raw(...)` when the
full response envelope is needed.

`base_url` defaults to `https://api.rafflesia.ai` (override via the `base_url`
argument or `RAFFLESIA_API_BASE_URL`). When no API key is configured the client
sends anonymous requests, which is convenient against a local unauthenticated
server.

## Layout

- `rafflesia/resources/`, `rafflesia/types/` — **generated** from the OpenAPI
  contract; do not edit by hand. Regenerate with
  `factory/generators/oagen/retab-gen` → `node scripts/generate-product.mjs python`.
- `rafflesia/client.py`, `rafflesia/_resource.py`, `rafflesia/exceptions.py`,
  `rafflesia/utils/` — hand-written runtime the emitter reuses; kept stable
  across regeneration (the emitter only prunes files it previously generated).
