Metadata-Version: 2.4
Name: vcti-cache
Version: 1.1.1
Summary: VCollab Cache - size-bounded object cache with pluggable eviction policies
Author: Visual Collaboration Technologies Inc.
Requires-Python: <3.15,>=3.12
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: test
Requires-Dist: pytest; extra == "test"
Requires-Dist: pytest-cov; extra == "test"
Provides-Extra: lint
Requires-Dist: ruff; extra == "lint"
Dynamic: license-file

# Object Cache

## Purpose

VCollab applications frequently need to hold computed or loaded objects
in memory with a bounded size budget. When the budget is exceeded, old
entries must be evicted according to a configurable policy.

The `vcti-cache` package provides `ObjectCache`, a generic,
size-bounded cache with a pluggable eviction policy defined by the
abstract `CachePolicy` base class. Implement `CachePolicy` to control
how item sizes are calculated and which items are evicted first.

This package has **zero external dependencies**.

---

## Installation

### From GitHub (recommended for development)

```bash
# Latest main branch
pip install vcti-cache


### From a GitHub Release

Download the wheel from the
[Releases](https://github.com/vcollab/vcti-python-cache/releases)
page and install directly:

```bash
pip install vcti-cache>=1.1.1
```

### In `requirements.txt`

```
vcti-cache>=1.1.1
```

### In `pyproject.toml` dependencies

```toml
dependencies = [
    "vcti-cache>=1.1.1",
]
```

---

## Quick Start

```python
from vcti.cache import ObjectCache, LruPolicy

# 1. Create a cache with a built-in LRU policy
cache = ObjectCache[str](max_size=100, cache_policy=LruPolicy(get_size=len))

# 2. Add, retrieve, and remove items
cache.add("greeting", "hello")
print(cache.get("greeting"))   # "hello"
print(cache["greeting"])       # "hello"  (bracket syntax)
print("greeting" in cache)     # True
print(len(cache))              # 1
print(cache.current_size)      # 5

# 3. Update (upsert) an existing item
cache.update("greeting", "hi there")
print(cache.get("greeting"))   # "hi there"

# 4. Inspect statistics
print(cache.stats.hits)        # 2  (from the get + bracket access)
print(cache.stats.adds)        # 2  (original add + update)

cache.remove("greeting")
print(cache.get("greeting"))   # None
```

Three bundled policies are available — `FifoPolicy`, `LruPolicy`,
`LfuPolicy` — each accepting a `get_size` callable.  For custom
eviction logic, subclass `CachePolicy[T]` directly (see
[Extending](docs/extending.md)).

---

## Thread Safety

`ObjectCache` is **not thread-safe**. If you share a cache across threads,
wrap it with an external lock (e.g. `threading.Lock`).

---

## Public API

| Symbol | Kind | Description |
|--------|------|-------------|
| `ObjectCache[T]` | Class | Size-bounded cache with eviction support |
| `CachePolicy[T]` | ABC | Abstract base for eviction strategies |
| `FifoPolicy[T]` | Policy | First-in-first-out eviction |
| `LruPolicy[T]` | Policy | Least-recently-used eviction |
| `LfuPolicy[T]` | Policy | Least-frequently-used eviction |
| `MruPolicy[T]` | Policy | Most-recently-used eviction (scan-resistant) |
| `RrPolicy[T]` | Policy | Random replacement (Bélády-immune) |
| `CacheStats` | Dataclass | Immutable hit/miss/eviction/removal statistics |
| `CacheOverflowError` | Exception | Raised when an item cannot fit |

### `ObjectCache[T]`

| Method / Property | Description |
|-------------------|-------------|
| `add(key, value)` | Insert an item; evicts if needed, raises on duplicate key |
| `update(key, value)` | Insert or replace an item (upsert); evicts if needed |
| `get(key)` | Retrieve by key or `None` |
| `cache[key]` | Retrieve by key or raise `KeyError` |
| `remove(key)` | Remove a single item (fires `on_remove`) |
| `clear()` | Remove all items |
| `keys()` | List of current keys |
| `values()` | List of current values |
| `items()` | List of `(key, value)` pairs |
| `iter(cache)` | Iterate over keys |
| `max_size` | Maximum capacity in bytes |
| `current_size` | Total size of cached items (bytes) |
| `get_item_size(key)` | Cached size of an item (bytes), or `None` if missing |
| `stats` | `CacheStats` instance with hit/miss/eviction counters |
| `policy` | The active `CachePolicy` instance |
| `key in cache` | Membership test |
| `len(cache)` | Number of cached items |

### `CachePolicy[T]` (abstract)

| Method | Override | Description |
|--------|----------|-------------|
| `get_size(item)` | Required | Return item size in bytes (>= 0) |
| `get_eviction_items(space, items)` | Required | Return keys to evict |
| `on_add(key, item)` | Optional | Called after an item is added |
| `on_access(key, item)` | Optional | Called when an item is retrieved |
| `on_evict(key, item)` | Optional | Called when an item is evicted by the policy |
| `on_remove(key, item)` | Optional | Called when an item is explicitly removed by the caller |

### `CacheStats`

| Field | Description |
|-------|-------------|
| `hits` | Successful `get` / `[]` calls |
| `misses` | `get` calls returning `None` / `[]` raising `KeyError` |
| `adds` | Successful `add` / `update` insertions |
| `evictions` | Items removed by the eviction policy |
| `removals` | Items explicitly removed by `remove()` / `clear()` / `update()` replacement |

### Bundled Policies

All bundled policies accept `get_size: Callable[[T], int]` in their
constructor.

| Policy | Eviction Rule | Internal Structure |
|--------|---------------|--------------------|
| `FifoPolicy[T]` | Oldest insertion first | `OrderedDict` |
| `LruPolicy[T]` | Least recently accessed | `OrderedDict` (moves on access) |
| `LfuPolicy[T]` | Lowest access count (ties: oldest) | `defaultdict(int)` + `OrderedDict` |
| `MruPolicy[T]` | Most recently accessed | `OrderedDict` (evicts from end) |
| `RrPolicy[T]` | Random (accepts optional `seed`) | `list` + `random.Random` |

**Start with `LruPolicy`** — it's the best general-purpose default.
See [Choosing a Policy](docs/design.md#choosing-a-policy) for a detailed
comparison of performance, trade-offs, and when to use each.

---

## Documentation

- [Design](docs/design.md) — Architecture, generic type parameter, and policy pattern
- [Source Guide](docs/source-guide.md) — File-by-file walkthrough
- [Patterns](docs/patterns.md) — Real-world usage recipes (LRU, statistics, etc.)
- [Extending](docs/extending.md) — How to write custom eviction policies
- [API Reference](docs/api.md) — Autodoc for all modules
