# Python client

```python
import runcompute
client = runcompute.Client()
```

`Client(api_key=None, base_url=None, timeout=30.0, max_retries=2)`. With no
arguments it uses `RUNCOMPUTE_API_KEY` or your saved login and
`https://runcompute.cloud`. It can be used as a context manager.

## Client methods

| Method | Returns |
| --- | --- |
| `run(**params)` | `Job`, accepted but not finished. See [parameters](/docs/parameters/) |
| `quote(**params)` | List of offers, cheapest estimate first. No key needed |
| `get(job_id)` | `Job` |
| `list(status=None, limit=50)` | List of `Job`. `status` is `"active"`, `"terminal"` or a status name |
| `wait(job_id, poll_seconds=2.0, timeout_seconds=None, progress=None)` | Finished `Job` |
| `cancel(job_id)` | `Job` |
| `logs(job_id, tail=0)` | Log text |
| `outputs(job_id)` | List of `Output` |
| `me()` | Account email and key prefix |

## Job

| Member | Description |
| --- | --- |
| `id`, `status`, `progress`, `spend`, `budget`, `attempts`, `offer` | Values from the last refresh |
| `succeeded` | `True` when status is `succeeded` |
| `done` | `True` for any final status |
| `refresh()` | Fetch the latest values |
| `wait(...)` | Poll until done. `progress=True` prints events to stderr. Ctrl+C cancels |
| `follow(poll_seconds=2.0)` | Generator yielding the job on each poll until done |
| `events(after=0)` | Event dictionaries with `seq`, `ts`, `kind`, `msg` |
| `logs(tail=0)` | Log text |
| `outputs()` | List of `Output(name, size_bytes, created)` |
| `cancel()` | Cancel and refresh |

## JobStatus

`runcompute.JobStatus` is a string enum: `QUEUED`, `RUNNING`, `RECOVERING`,
`SUCCEEDED`, `STOPPED`, `FAILED`, `CANCELLED`. `status.terminal` is `True` for
the last four.

## Errors

API errors raise `runcompute.APIError` with `status` and `detail`. A
`TimeoutError` is raised when `wait(timeout_seconds=...)` runs out; the job
keeps running.
