Metadata-Version: 2.4
Name: metrana
Version: 0.0.5
Summary: Inephany client library to use Metrana.
Author-email: Inephany <info@inephany.com>
License: Apache 2.0
Keywords: metrana,mlops,rlops,ml,metrics
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy<2.0.0,>=1.24.0
Requires-Dist: loguru<0.8.0,>=0.7.0
Requires-Dist: requests<3.0.0,>=2.28.0
Requires-Dist: pydantic<3.0.0,>=2.5.0
Requires-Dist: urllib3<3.0.0,>=2.0.0
Requires-Dist: PyYAML<7.0.0,>=6.0.0
Requires-Dist: aiohttp<4.0.0,>=3.0.0
Requires-Dist: metrana-protobuf<1.0.0,>=0.0.0
Provides-Extra: dev
Requires-Dist: pytest<9.0.0,>=7.0.0; extra == "dev"
Requires-Dist: pytest-mock<4.0.0,>=3.10.0; extra == "dev"
Requires-Dist: bump-my-version==0.11.0; extra == "dev"
Requires-Dist: black==24.4.2; extra == "dev"
Requires-Dist: isort==5.9.3; extra == "dev"
Requires-Dist: flake8==7.1.0; extra == "dev"
Requires-Dist: pre-commit==4.0.1; extra == "dev"
Requires-Dist: mypy==1.13.0; extra == "dev"
Requires-Dist: types-PyYAML>=6.0.12; extra == "dev"
Requires-Dist: types-redis>=4.5.0; extra == "dev"
Requires-Dist: types-requests>=2.28.0; extra == "dev"
Requires-Dist: types-cachetools>=6.1.0; extra == "dev"
Requires-Dist: typeguard==4.3.0; extra == "dev"
Requires-Dist: pytest-asyncio<1.0.0,>=0.23.0; extra == "dev"
Dynamic: license-file

# Metrana Client Library

Metrana is a metrics tracking client for ML/RL training runs. It provides a simple three-function API to log metrics from training loops to the Metrana ingestion service, with asynchronous batching, configurable backpressure handling, and automatic retry on failure.

## Installation

```bash
pip install metrana
```

The `metrana-protobuf` dependency is pulled in automatically.

## Quick Start

```python
import metrana

metrana.init(
    api_key="your-api-key",
    workspace_name="my-workspace",
    project_name="my-project",
    run_name="run-001",
)

for step in range(1000):
    loss, accuracy = train_step()
    metrana.log("loss", loss)
    metrana.log("accuracy", accuracy)

metrana.close()
```

The API key can also be provided via the `METRANA_API_KEY` environment variable, in which case `api_key` can be omitted from `init()`.

## API Reference

### `metrana.init()`

Initialises the logger. Must be called once before `log()` or `close()`.

```python
metrana.init(
    api_key: str,
    workspace_name: str,
    project_name: str,
    run_name: str,
    experiment_name: str | None = None,

    # Behavioural strategies (can also be set via environment variables)
    resume_strategy: str | None = None,       # "Never" | "Allow"
    backpressure_strategy: str | None = None, # "DropNew" | "Block" | "Raise"
    error_strategy: str | None = None,        # "Silent" | "Warn" | "RaiseOnLog" | "RaiseOnClose"
    close_strategy: str | None = None,        # "Immediate" | "CompletePending" | "CompleteAll"
    log_level: str | None = None,             # "Trace" | "Debug" | "Info" | "Success" | "Warn" | "Error" | "Critical" | "Off"

    # Advanced
    num_dispatch_workers: int = 4,
    ingestion_url: str | None = None,         # Overrides the default API endpoint
)
```

### `metrana.log()`

Logs a single metric value. Thread-safe and non-blocking by default.

```python
metrana.log(
    metric_name: str,           # Name of the metric series
    value: float | int,         # Metric value
    scale: str | None = None,   # "ML_STEP" | "EPISODE" | "ENVIRONMENT_STEP" (default: "ML_STEP")
    step: int | None = None,    # Explicit step index; auto-increments per series if omitted
    labels: dict[str, str] | None = None,  # Additional series labels
    timestamp: int | None = None,          # Unix nanoseconds; defaults to now
)
```

### `metrana.close()`

Shuts down the logger. Behaviour depends on the configured `close_strategy`.

```python
metrana.close()
```

## Metric Scales

| Scale | Use when |
|---|---|
| `ML_STEP` | One entry per gradient update / training step (default) |
| `EPISODE` | One entry per RL episode |
| `ENVIRONMENT_STEP` | One entry per RL environment interaction |

Pass the scale name as a string or use `metrana.StandardMetricScale`:

```python
from metrana import StandardMetricScale
metrana.log("reward", reward, scale=StandardMetricScale.EPISODE)
```

## Strategies

### Backpressure strategy

Controls what happens when the internal event queue is full.

| Value | Behaviour |
|---|---|
| `DropNew` | Silently discard the incoming event (default) |
| `Block` | Block the calling thread until space is available |
| `Raise` | Raise `MetranaEventQueueFullError` |

### Error strategy

Controls how API errors are surfaced to the caller.

| Value | Behaviour |
|---|---|
| `Silent` | Ignore errors |
| `Warn` | Log a warning and continue (default) |
| `RaiseOnLog` | Raise on the next `log()` call if errors have occurred |
| `RaiseOnClose` | Raise on `close()` if errors have occurred |

### Resume strategy

Controls what happens when a run with the same name already exists.

| Value | Behaviour |
|---|---|
| `Allow` | Create a new run or resume an existing one (default) |
| `Never` | Always create a new run; raise if it already exists |

### Close strategy

Controls how pending events are handled on shutdown.

| Value | Behaviour |
|---|---|
| `Immediate` | Shut down immediately, discarding pending events |
| `CompletePending` | Complete API requests already in flight, but discard events still queued (default) |
| `CompleteAll` | Wait for all queued events including those not yet dispatched |

## Environment Variables

All strategies and several other settings can be configured without code changes:

| Variable | Default | Accepted values |
|---|---|---|
| `METRANA_API_KEY` | — | Your API key |
| `METRANA_BACKPRESSURE_STRATEGY` | `DropNew` | `DropNew`, `Block`, `Raise` |
| `METRANA_ERROR_MODES` | `Warn` | `Silent`, `Warn`, `RaiseOnLog`, `RaiseOnClose` |
| `METRANA_RESUME_STRATEGY` | `Allow` | `Allow`, `Never` |
| `METRANA_CLOSE_STRATEGY` | `CompletePending` | `Immediate`, `CompletePending`, `CompleteAll` |
| `METRANA_LOG_LEVEL` | `Success` | `Trace`, `Debug`, `Info`, `Success`, `Warn`, `Error`, `Critical`, `Off` |
| `METRANA_EVENT_QUEUE_MAX_SIZE` | unbounded | Integer (`0` = unbounded) |
| `METRANA_DISPATCH_QUEUE_MAX_SIZE` | unbounded | Integer (`0` = unbounded) |
| `METRANA_ERROR_QUEUE_MAX_SIZE` | unbounded | Integer (`0` = unbounded) |
