Metadata-Version: 2.4
Name: riffsdk
Version: 0.12.1
Summary: Python SDK for the Riff Storage API
Project-URL: Homepage, https://riff.ai
Author-email: Martin Sandve Alnæs <msa@databutton.io>
License-Expression: MIT
License-File: LICENCE
Requires-Python: >=3.11
Requires-Dist: httpx>=0.27
Requires-Dist: pydantic>=2.6
Requires-Dist: tenacity>=8.3
Description-Content-Type: text/markdown

# riffsdk

Python SDK for the Riff Storage API. Provides sync and async clients for storing, retrieving, and managing objects.

## Installation

```bash
uv add riffsdk
# or
pip install riffsdk
```

Or install from a branch (for pre-release testing):

```bash
uv add git+https://github.com/databutton/riff-sdk-python.git@main
# or
pip install git+https://github.com/databutton/riff-sdk-python.git@main
```

## Quick start

```python
from riffsdk.storage import StorageClient

client = StorageClient()

# Upload
meta = client.put("hello.txt", "Hello, world!")

# Download
data = client.get("hello.txt")

# List
for obj in client.list("hello"):
    print(f"{obj.key} ({obj.size} bytes)")

# Delete
client.delete("hello.txt")

client.close()
```

### Async

```python
from riffsdk.storage import AsyncStorageClient

async with AsyncStorageClient() as client:
    await client.put("key", b"data", content_type="application/octet-stream")
    data = await client.get("key")
```

## Authentication

Set the `RIFF_TOKEN` environment variable. The SDK picks it up automatically.

## API

### Clients

- `StorageClient` -- sync client
- `AsyncStorageClient` -- async client

Both support: `put`, `get`, `stat`, `exists`, `list`, `delete`, `close`, and context manager usage.

### Models

- `ObjectMeta` -- metadata for a stored object (key, version, size, content_type, timestamps)
- `UploadResult`, `DownloadResult` -- operation results
- `ListPage` -- paginated listing
- `Scope` -- access scope (use `account_scope()`, `project_scope()`, `session_scope()`)

### Uploads

- `ResumableUpload` / `AsyncResumableUpload` -- multipart resumable uploads for large files
- `StorageReader` / `StorageWriter` -- streaming read/write

### Exceptions

All exceptions inherit from `StorageError`:

- `AuthorisationError`
- `ObjectNotFoundError`
- `VersionConflictError`
- `AlreadyExistsError`
- `LeaseConflictError`
- `UploadNotFoundError`
- `QuotaExceededError`
- `PartMismatchError`
- `StorageTransportError`

## Examples

See the `examples/` directory for complete working examples:

- `basic_crud.py` -- put, get, list, delete
- `async_client.py` -- async usage with asyncio
- `file_upload_download.py` -- file uploads with progress
- `optimistic_concurrency.py` -- version-based conflict handling

## Development

Requires Python 3.11+ and [uv](https://docs.astral.sh/uv/).

```bash
uv sync --dev        # Install dependencies
mise run test        # Run tests
mise run lint        # Lint
mise run format      # Format code
```

See `AGENTS.md` for full development workflow details.
