Metadata-Version: 2.3
Name: syvain-metrics-api-client
Version: 0.0.379
Summary: Python client for the Syvain Metrics v2 API
Requires-Dist: niquests>=3.16.0
Requires-Dist: pydantic>=2.13.3
Requires-Dist: pytest>=8.0.0 ; extra == 'dev'
Requires-Dist: ruff>=0.15.12 ; extra == 'dev'
Requires-Dist: ty>=0.0.34 ; extra == 'dev'
Requires-Python: >=3.14, <3.15
Provides-Extra: dev
Description-Content-Type: text/markdown

# Syvain Metrics API Client

Python client for the [Syvain Metrics](https://metrics.syvain.com/) v2 API.
Use it to find and organize folders and experiments and to read one
experiment's record, catalog, annotations, and series from code.

Pick the right tool:

- **Analysis across experiments:** the `syvain-metrics-duckdb` extension
  attaches Metrics as a database with an on-disk cache. Use it for plots,
  tables, joins, and anything spanning a folder.
- **Recording training or evaluation jobs:** `syvain-metrics-collector` queues,
  batches, and delivers metrics in the background. This client's write session
  exists for API completeness, tests, and backfills.
- **Programmatic control and one-experiment reads:** this client.

## Install

```bash
uv add syvain-metrics-api-client
```

## Connect

```python
from syvain_metrics_api_client import Metrics

metrics = Metrics()
```

The client resolves credentials the same way as the `syvain-metrics` CLI. The
API key comes from `api_key=`, then `SYVAIN_METRICS_API_KEY`, then the login
saved by `syvain-metrics auth login`. The host comes from `host=`, then
`SYVAIN_METRICS_HOST`, then that login, then `https://metrics.syvain.com`.
`Metrics` is also a context manager that closes its HTTP session.

## Folders and experiments

Address a folder by absolute path or id; `/` is the root. Address an experiment
by id or slug.

```python
mamba = metrics.make_folder("/models/mamba")  # creates missing parents
mamba = metrics.folder("/models/mamba")       # MetricsNotFound when missing
mamba.folders()                               # direct children
mamba.experiments()                           # direct members
mamba.experiments("run-*", recursive=True)    # slug glob, whole subtree
metrics.experiments("syv-2039-*")             # every experiment matching a glob

exp = metrics.experiment("mamba-run-001")
exp.move("/archive")
mamba.rename("mamba-v2")
mamba.move("/")
```

Lookups use a snapshot of the folder tree, read on first use. Changes made
through the client refresh it. A `folder()` or `experiment()` lookup that
misses reads the tree again once before raising. Listings such as
`folders()` and `experiments()` use the snapshot as is, so call
`metrics.refresh()` to list what was created elsewhere. `Folder` and
`Experiment` are immutable values. A rename or move returns a new handle.

## Read one experiment

```python
info = exp.info()          # status, description, meta, error, lifecycle datetimes
catalog = exp.catalog()    # series names with their metadata keys and values
notes = exp.annotations()  # every annotation, newest first

for series in exp.series("loss", where={"split": "valid"}):
    print(series.metadata, series.steps, series.values)
```

`series()` returns one `Series` per metadata partition. Its `steps`,
`timestamps_ms`, and `values` are aligned. Pass one name, several names, or
none to read every series of the experiment. Results follow the order of the
names, or name order when you pass none. One streaming request reads up to
1,000 series. `where` matches exact metadata values, `has=("rank",)` requires a
key, and `x="timestamp"` orders points by time instead of step. The client
returns series only after the stream completes, so partial data is never
returned.

## Write session

```python
with metrics.open_experiment(
    "backfill-001", description="Imported run", meta={"seed": 7}, folder="/imports"
) as run:
    run.start()
    run.metric("loss", 0.25, step=1, metadata={"split": "train"})
    run.done()
```

Each call is one acknowledged request. `metrics()` takes many `MetricPoint`s
and sends up to 1000 per request. The session refreshes its experiment token
before it expires and revokes the token when the block exits. Reopening an
existing slug replaces its description and meta. An experiment already in
another folder stays there. A token left idle past its 24 hour expiry cannot be
refreshed, so reopen the experiment instead. For real training jobs use
`syvain-metrics-collector`.

## Other events

`metrics.send(event, data)` sends any v2 organization event to
`/api/v2/events` and returns the reply data. The API reference is at
`https://metrics.syvain.com/api/openapi.json`.

## Errors and retries

Every failure is a `MetricsError` with `code`, `message`, `status`, and
`retryable`. `MetricsNotFound` (also a `LookupError`) reports an unresolved
reference. `MetricsAuthError` reports missing credentials.

Reads and metric writes retry transient failures with backoff. A retried
metric keeps its original message id, which the API deduplicates. Every other
write never retries, because repeating it can have side effects: folder
creation, moves, renames, `open_experiment`, lifecycle events (a replayed
`done` would move `done_at`), annotations, and `send()`.
