Metadata-Version: 2.4
Name: kelvin-app-storage
Version: 1.0.0
Summary: Library for storing and retrieving state of Kelvin applications.
Author-email: Kelvin Inc <engineering@kelvininc.com>
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Requires-Python: >=3.12
Description-Content-Type: text/markdown
Requires-Dist: pyyaml==6.0.3
Requires-Dist: redis[hiredis]==7.1.0
Requires-Dist: structlog==25.5.0

# kelvin-app-storage

Redis-backed storage client for Kelvin applications. Keys are automatically prefixed with the application name and version derived from `app.yaml`.

## Installation

```bash
pip install kelvin-app-storage
```

## Prerequisites

A running Redis instance is required. For local development:

```bash
docker run -d --name redis -p 6379:6379 redis
```

## Quick Start

```python
from kelvin_app_storage import StorageClient

client = StorageClient()

# Store and retrieve values
client.set("sensor_id", "abc-123")
client.get("sensor_id")  # "abc-123"

# List all stored keys
client.list_keys()  # ["myapp_1.0_sensor_id"]

# Print a formatted table of all stored key-value pairs
print(client)
```

### Disable Key Prefixing

By default, keys are prefixed with `<app_name>_<app_version>_` derived from `app.yaml`. To store keys without a prefix:

```python
client = StorageClient(no_prefix=True)
```

## Supported Value Types

The client automatically serializes and deserializes the following types:

| Type | Storage Format |
|---|---|
| `str` | Stored as-is |
| `int` | String representation |
| `float` | String representation |
| `bool` | `"true"` / `"false"` |
| `list` | JSON string |
| `dict` | JSON string |

```python
client.set("count", 42)
client.get("count")  # 42

client.set("config", {"threshold": 0.8, "enabled": True})
client.get("config")  # {"threshold": 0.8, "enabled": True}

client.set("tags", ["pressure", "temperature"])
client.get("tags")  # ["pressure", "temperature"]
```

## Configuration

The client is configured via environment variables:

| Environment Variable | Default | Description |
|---|---|---|
| `KELVIN_APP_STORAGE_HOST` | `kelvin-app-storage.app` | Redis host |
| `KELVIN_APP_STORAGE_PORT` | `6379` | Redis port |
| `KELVIN_APP_STORAGE_PREFIX` | Derived from `app.yaml` | Custom key prefix (overrides `app.yaml`) |
| `KELVIN_APP_STORAGE_LOG_LEVEL` | `INFO` | Log level (`DEBUG` or `INFO`) |

### Key Prefix via `app.yaml`

When no custom prefix is set, the key prefix is derived from `app.yaml` in the current working directory:

```yaml
info:
  name: myapp
  version: "1.0"
```

This produces the prefix `myapp_1.0`, so a key `sensor_id` becomes `myapp_1.0_sensor_id` in Redis.

If `app.yaml` is missing or unreadable, a random UUID is used as the fallback prefix.

## API Reference

### `StorageClient(no_prefix: bool = False)`

Creates a new storage client and connects to Redis.

- **`no_prefix`** -- If `True`, keys are stored without any prefix.
- Raises `ValueError` if `KELVIN_APP_STORAGE_PORT` is not a valid integer.
- Raises `redis.ConnectionError` if Redis is unreachable.

### `client.get(key: str) -> Any`

Retrieves and deserializes the value for the given key. Returns `None` if the key does not exist.

### `client.set(key: str, value: Any) -> bool`

Serializes and stores a value. Returns `True` on success. Raises `TypeError` for unsupported value types.

### `client.list_keys() -> list`

Returns all keys currently stored in Redis.
