Metadata-Version: 2.4
Name: picocache
Version: 0.2.0
Summary: persistent decorators mirroring functools.lru_cache
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: redis>=5.2.1
Requires-Dist: sqlalchemy>=2.0.40

# PicoCache

**Persistent, datastore‑backed `lru_cache` for Python.**  
PicoCache gives you the ergonomics of `functools.lru_cache` while keeping your
cached values safe across process restarts and even across machines.  
Two back‑ends are provided out of the box:

- **SQLAlchemyCache** – persists to any RDBMS supported by
  [SQLAlchemy](https://www.sqlalchemy.org/) (SQLite, Postgres, MySQL, …).
- **RedisCache** – stores values in [Redis](https://redis.io/), perfect for
  distributed deployments.

---

## Why PicoCache?

- **Familiar API** – decorators feel _identical_ to `functools.lru_cache`.
- **Durable** – survive restarts, scale horizontally.
- **Introspectable** – `cache_info()` and `cache_clear()` just like the
  standard library.
- **Zero boilerplate** – pass a connection URL and start decorating.

---

## Installation

```bash
pip install picocache
```

---

## Quick‑start

### 1. SQL (SQLite example)

```python
from picocache import SQLAlchemyCache

# Create the decorator bound to an SQLite file
sql_cache = SQLAlchemyCache("sqlite:///cache.db")

@sql_cache(maxsize=256)        # feels just like functools.lru_cache
def fib(n: int) -> int:
    return n if n < 2 else fib(n - 1) + fib(n - 2)
```

### 2. Redis

```python
from picocache import RedisCache

redis_cache = RedisCache("redis://localhost:6379/0")

@redis_cache(maxsize=128, typed=True)
def slow_add(a: int, b: int) -> int:
    print("Executing body…")
    return a + b
```

On the second call with the same arguments, `slow_add()` returns instantly and
_“Executing body…”_ is **not** printed – the result came from Redis.

---

## API

Each decorator object is initialised with connection details and **called** with
the same signature as `functools.lru_cache`:

```python
SQLAlchemyCache(url_or_engine, *, key_serializer=None, value_serializer=None, ...)
RedisCache(url_or_params, *, key_serializer=None, value_serializer=None, ...)
```

### `__call__(maxsize=128, typed=False)`

Returns a decorator that memoises the target function.

| Param     | Type         | Default | Meaning                                                            |
| --------- | ------------ | ------- | ------------------------------------------------------------------ |
| `maxsize` | `int`/`None` | `128`   | Per‑function entry limit (`None` → no limit).                      |
| `typed`   | `bool`       | `False` | Treat arguments with different types as distinct (same as stdlib). |

The wrapped function gains:

- **`.cache_info()`** → `namedtuple(hits, misses, currsize, maxsize)`
- **`.cache_clear()`** → empties the persistent store for that function.

---

## Running the tests

```bash
uv sync
just test
```

- SQL tests run against an **in‑memory** SQLite DB (no external services).
- Redis tests are skipped automatically unless a Redis server is available on
  `localhost:6379`.

---

## License

MIT – see [LICENSE](LICENSE) for details.

