> ## Documentation Index
> Fetch the complete documentation index at: https://avala.ai/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Python SDK

> Vollständiger Guide für das Avala Python SDK

<Info>Das Python SDK erfordert **Python 3.9+**.</Info>

## Installation

```bash theme={null}
pip install avala
```

## Schnellstart

```python theme={null}
from avala import Client

client = Client(api_key="your-api-key")

# Alle Datensätze auflisten
datasets = client.datasets.list()
for dataset in datasets:
    print(dataset.name, dataset.uid)
```

## Konto erstellen

Die Funktion `signup` erstellt ein neues Avala-Konto und gibt einen API Key zurück. Sie erfordert keine Authentifizierung.

```python theme={null}
from avala import signup

result = signup(
    email="dev@acme.com",
    password="SecurePass123!",
    first_name="Jane",       # optional
    last_name="Doe",         # optional
)

print(f"User: {result.user.email}")
print(f"API Key: {result.api_key}")
```

Eine asynchrone Variante ist ebenfalls verfügbar:

```python theme={null}
from avala import async_signup

result = await async_signup(email="dev@acme.com", password="SecurePass123!")
```

## Authentifizierung

Das SDK authentifiziert sich mit Ihrem Avala API Key, der über den `X-Avala-Api-Key` Header bei jeder Anfrage gesendet wird.

Sie können den Key direkt übergeben oder das SDK ihn aus der Umgebung lesen lassen.

**Option 1: Key direkt übergeben**

```python theme={null}
from avala import Client

client = Client(api_key="your-api-key")
```

**Option 2: Umgebungsvariable verwenden**

```bash theme={null}
export AVALA_API_KEY="your-api-key"
```

```python theme={null}
from avala import Client

# Liest automatisch AVALA_API_KEY aus der Umgebung
client = Client()
```

## Async-Unterstützung

Das SDK enthält einen vollständig asynchronen Client, der auf `httpx` basiert. Verwenden Sie `AsyncClient` für nicht-blockierende I/O in asynchronen Anwendungen.

```python theme={null}
import asyncio
from avala import AsyncClient

async def main():
    client = AsyncClient(api_key="your-api-key")

    datasets = await client.datasets.list()
    for dataset in datasets:
        print(dataset.name)

    # Client immer schließen wenn fertig, oder als Context Manager verwenden
    await client.close()

asyncio.run(main())
```

**Verwendung des Async Context Managers:**

```python theme={null}
import asyncio
from avala import AsyncClient

async def main():
    async with AsyncClient() as client:
        datasets = await client.datasets.list()
        for dataset in datasets:
            print(dataset.name)

asyncio.run(main())
```

## Arbeiten mit Datensätzen

<Note>
  Das Python SDK ist derzeit **schreibgeschützt für Datensätze** — Sie können auflisten, abrufen und Elemente durchsuchen, aber keine Datensätze erstellen oder löschen. Verwenden Sie die [REST API](/docs/sdks/rest-api#file-uploads) für Uploads und Mutationen.
</Note>

### Datensätze auflisten

```python theme={null}
datasets = client.datasets.list()

for dataset in datasets:
    print(f"{dataset.name} ({dataset.uid})")
    print(f"  Elemente: {dataset.item_count}")
    print(f"  Erstellt: {dataset.created_at}")
```

### Datensatz abrufen

```python theme={null}
dataset = client.datasets.get("550e8400-e29b-41d4-a716-446655440000")

print(dataset.name)
print(dataset.slug)
print(dataset.item_count)
```

## Arbeiten mit Projekten

### Projekte auflisten

```python theme={null}
projects = client.projects.list()

for project in projects:
    print(f"{project.name} ({project.uid})")
    print(f"  Status: {project.status}")
    print(f"  Erstellt: {project.created_at}")
```

### Projekt abrufen

```python theme={null}
project = client.projects.get("770a9600-a40d-63f6-c938-668877660000")

print(project.name)
print(project.status)
```

## Arbeiten mit Aufgaben

### Aufgaben auflisten

```python theme={null}
tasks = client.tasks.list(project="770a9600-a40d-63f6-c938-668877660000", status="pending")

for task in tasks:
    print(f"{task.uid} — {task.name} ({task.status})")
```

### Aufgabe abrufen

```python theme={null}
task = client.tasks.get("990c1800-b62f-85a8-e150-880099880000")

print(task.name)
print(task.status)
```

## Arbeiten mit Exporten

<Note>
  Das Python SDK unterstützt vollständige CRUD-Operationen für Agents, Webhooks, Speicherkonfigurationen, Inferenz-Provider, Qualitätsziele, Konsenskonfiguration und Organisationen. Datensätze und Projekte sind derzeit schreibgeschützt — verwenden Sie die [REST API](/docs/sdks/rest-api) für Mutationen bei diesen Ressourcen.
</Note>

### Export erstellen

```python theme={null}
export = client.exports.create(project="770a9600-a40d-63f6-c938-668877660000")

print(f"Export gestartet: {export.uid}")
print(f"Status: {export.status}")
```

### Auf Fertigstellung warten

```python theme={null}
import time

export = client.exports.create(project="770a9600-a40d-63f6-c938-668877660000")

while export.status != "completed":
    time.sleep(2)
    export = client.exports.get(export.uid)
    print(f"Status: {export.status}")

print(f"Download: {export.download_url}")
```

## Arbeiten mit Organisationen

### Organisationen auflisten

```python theme={null}
orgs = client.organizations.list()
for org in orgs:
    print(f"{org.name} ({org.slug})")
```

### Organisation erstellen

```python theme={null}
org = client.organizations.create(name="My Team", visibility="private", industry="technology")
print(f"Erstellt: {org.name} ({org.uid})")
```

### Mitglieder verwalten

```python theme={null}
members = client.organizations.list_members("my-team")
for member in members:
    print(f"{member.full_name} - {member.role}")
```

## Arbeiten mit Slices

### Slices auflisten

```python theme={null}
slices = client.slices.list("my-org")
for s in slices:
    print(f"{s.name}: {s.item_count} Elemente")
```

## Datensatz-Elemente durchsuchen

### Elemente in einem Datensatz auflisten

```python theme={null}
items = client.datasets.list_items("my-org", "my-dataset")
for item in items:
    print(f"{item.uid}: {item.key}")
```

### Sequenzen auflisten

```python theme={null}
sequences = client.datasets.list_sequences("my-org", "my-dataset")
for seq in sequences:
    print(f"{seq.uid}: {seq.key} ({seq.number_of_frames} Frames)")
```

## Type Hints

Das SDK ist vollständig typisiert. Alle Antwortobjekte sind Pydantic-Modelle mit vollständigen Typannotationen, die Ihnen Autovervollständigung und Typprüfung sofort ermöglichen.

```python theme={null}
from avala.types import Dataset, Project, Export, Task

def process_dataset(dataset: Dataset) -> None:
    print(dataset.name)        # str
    print(dataset.uid)         # str
    print(dataset.item_count)  # int
    print(dataset.created_at)  # Optional[datetime]

def process_task(task: Task) -> None:
    print(task.uid)            # str
    print(task.name)           # Optional[str]
    print(task.status)         # Optional[str]
    print(task.project)        # Optional[str]
```

## Fehlerbehandlung

Das SDK wirft typisierte Exceptions, sodass Sie verschiedene Fehlermodi präzise behandeln können.

```python theme={null}
from avala import Client
from avala.errors import (
    AvalaError,
    NotFoundError,
    RateLimitError,
    ValidationError,
)

client = Client()

try:
    dataset = client.datasets.get("nonexistent")
except NotFoundError as e:
    print(f"Datensatz nicht gefunden: {e.message}")
except RateLimitError as e:
    print(f"Rate-Limit erreicht. Erneut versuchen nach {e.retry_after} Sekunden.")
except ValidationError as e:
    print(f"Ungültige Anfrage: {e.message}")
    for detail in e.details:
        print(f"  - {detail}")
except AvalaError as e:
    # Auffang für alle anderen Avala API-Fehler
    print(f"API-Fehler ({e.status_code}): {e.message}")
```

| Exception             | Beschreibung                                                                                                                 |
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `AvalaError`          | Basis-Exception für alle Avala API-Fehler.                                                                                   |
| `AuthenticationError` | Ungültiger oder fehlender API Key (HTTP 401).                                                                                |
| `NotFoundError`       | Die angeforderte Ressource existiert nicht (HTTP 404).                                                                       |
| `RateLimitError`      | Das API-Rate-Limit wurde überschritten (HTTP 429). Enthält ein `retry_after`-Attribut.                                       |
| `ValidationError`     | Die Anfrage hat die Validierung nicht bestanden (HTTP 400/422). Enthält ein `details`-Attribut mit feldspezifischen Fehlern. |
| `ServerError`         | Der Server hat einen internen Fehler zurückgegeben (HTTP 5xx).                                                               |

## Paginierung

Listen-Methoden geben ein `CursorPage`-Objekt zurück. Sie können direkt über Elemente iterieren oder die Paginierung manuell steuern.

```python theme={null}
# Über Elemente auf der aktuellen Seite iterieren
for dataset in client.datasets.list():
    print(dataset.name)

# Manuelle Paginierung — Seitengröße steuern und auf Cursor zugreifen
page = client.datasets.list(limit=10)
for dataset in page.items:
    print(dataset.name)

# Nächste Seite abrufen
if page.has_more:
    next_page = client.datasets.list(limit=10, cursor=page.next_cursor)
```

## Flottenmanagement

<Info>
  Flottenmanagement ist in der Vorschau. Die hier beschriebenen APIs können sich ändern.
</Info>

Der `fleet`-Namespace bietet Zugriff auf Geräteregister, Aufnahmen, Events, Regeln und Warnungen.

```python theme={null}
# Online-Geräte auflisten
devices = client.fleet.devices.list(status="online")

# Ein Zeitleisten-Event auf einer Aufnahme erstellen
event = client.fleet.events.create(
    recording_id="rec_abc123",
    timestamp="2026-01-15T10:30:00Z",
    type="anomaly",
    label="Gripper force spike",
    metadata={"force_n": 45.2}
)

# Eine Aufnahmeregel erstellen
rule = client.fleet.rules.create(
    name="High Latency Alert",
    condition={"type": "threshold", "topic": "/diagnostics/latency", "field": "data.value", "operator": "gt", "value": 100},
    actions=[{"type": "tag", "value": "high-latency"}, {"type": "notify", "channel_id": "ch_your_channel_id"}]
)
```

Siehe den [Fleet Dashboard](/docs/visualization/fleet/fleet-dashboard) Guide für vollständige Beispiele.

## Konfiguration

Sie können das Client-Verhalten bei der Initialisierung anpassen.

```python theme={null}
from avala import Client

client = Client(
    api_key="your-api-key",
    base_url="https://api.avala.ai/api/v1",  # Standard
    timeout=60,        # Request-Timeout in Sekunden (Standard: 30)
    max_retries=3,     # Anzahl der Wiederholungsversuche bei transienten Fehlern (Standard: 2)
)
```

| Parameter     | Typ     | Standard                          | Beschreibung                                                                        |
| ------------- | ------- | --------------------------------- | ----------------------------------------------------------------------------------- |
| `api_key`     | `str`   | `AVALA_API_KEY` Umgebungsvariable | Ihr Avala API Key.                                                                  |
| `base_url`    | `str`   | `https://api.avala.ai/api/v1`     | Die API-Basis-URL.                                                                  |
| `timeout`     | `float` | `30`                              | Request-Timeout in Sekunden.                                                        |
| `max_retries` | `int`   | `2`                               | Anzahl automatischer Wiederholungsversuche bei transienten Fehlern (5xx, Timeouts). |
