Metadata-Version: 2.3
Name: pydantic-cacheable-model
Version: 2.0.1
Summary: Small Pydantic helpers for cacheable models
Author: J.I. Cruz
Author-email: J.I. Cruz <ji@jicruz.com>
Requires-Dist: pydantic>=2.11.7
Requires-Dist: typing-extensions>=4.6 ; python_full_version < '3.11'
Requires-Python: >=3.10
Description-Content-Type: text/markdown

# pydantic-cacheable-model

Small helpers to make your **Pydantic v2** models trivially cacheable to disk.

---

## Installation

```bash
pip install pydantic-cacheable-model
```

Supports Python **3.10+**

---

## Usage

```py
from __future__ import annotations
from datetime import datetime
from pydantic_cacheable_model import CacheableModel, CacheKey

class UserModel(CacheableModel):
    email: CacheKey[str]  # <- used as the cache key
    joined: datetime

# Create and cache to disk
u = UserModel(email="alice@example.com", joined=datetime.now())
u.cache()

# Load a single item by key
u2 = UserModel.load(cache_key="alice@example.com")
assert u2 == u

# Optionally handle missing caches or validation mismatches
maybe_user = UserModel.load(cache_key="missing@example.com", not_found_ok=True)

# List everything cached
all_users = UserModel.load_all_cached()
```

---

## Configuration

Below are the configuration knobs you can use. This single block shows all options; pick the ones you need.

```py
from __future__ import annotations
from datetime import datetime
from pydantic_cacheable_model import CacheableModel, CacheKey

# 1) Customize cache root and directory name
class UserModel(CacheableModel):
    # Change root directory (default: ".cache")
    CACHE_ROOT = ".data-cache"

    # Force a specific subdirectory name (otherwise derived from class name)
    CACHE_DIRNAME = "users"

    email: CacheKey[str]
    joined: datetime


# 2) Customize filename mapping (avoid if ids contain unsafe characters)
class FriendlyFilenames(CacheableModel):
    slug: CacheKey[str]

    @classmethod
    def cache_key_to_filename(cls, *, cache_key: str) -> str:
        # Default uses a SHA-256 hash; this stores plain ids instead
        return f"{cache_key}.json"


# 3) Custom key logic without using CacheKey
class Document(CacheableModel):
    kind: str
    slug: str

    @property
    def cache_key(self) -> str:
        return f"{self.kind}/{self.slug}"
```

---

## How It Works

- Cache location: `./.cache/<model-dir>/` by default. `<model-dir>` is derived from the class name, removing a trailing `Model` and converting CamelCase to kebab-case (e.g., `UserModel` → `user`, `LongNameModel` → `long-name`).
- File naming: `sha256(cache_key).json` for safe, stable filenames.
- Data format: pretty-printed JSON. `Enum` values and `datetime` objects serialize automatically.
- Choosing the key: mark one field with `CacheKey[T]`. If you need custom logic, override the `cache_key` property instead.

---

## API

- `CACHE_ROOT: str` — class var; default `".cache"`.
- `CACHE_DIRNAME: str | None` — class var; override to force subdirectory name. If `None`, derived from the class name.
- `cache_dir_path() -> str` — directory path where this model caches files.
- `cache_key_to_filename(*, cache_key: str) -> str` — classmethod; maps a key to a filename (default: SHA-256 hex + `.json`).
- `get_cache_path(*, cache_key: str) -> str` — full path to the cache file for a given key.
- `load(*, cache_key: str, not_found_ok: bool = False, warn_mismatch: bool = True) -> Self | None` — load and validate. If `not_found_ok=True`, returns `None` on missing or, when validation fails, returns `None` and optionally warns.
- `load_all_cached() -> list[Self]` — load all cached instances for the model.
- `cache() -> None` — write the instance to disk.
- `cache_path: str` — the path where this instance is cached.

---

## License

MIT — free to use and modify.
