Metadata-Version: 2.4
Name: gri-memoize
Version: 0.2.2
Summary: Per-instance memoization for class methods with full type hint preservation
Project-URL: Homepage, https://geosolresearch.com
Project-URL: Repository, https://gitlab.com/geosol-foss/python/gri-memoize
Project-URL: Issues, https://gitlab.com/geosol-foss/python/gri-memoize/-/issues
Project-URL: Changelog, https://gitlab.com/geosol-foss/python/gri-memoize/-/releases
Author-email: GeoSol Research Inc <contact@geosolresearch.com>
License-Expression: MIT
License-File: LICENSE
Keywords: caching,decorator,memoization,type-hints
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.12
Description-Content-Type: text/markdown

[![GeoSol Research Logo](https://geosolresearch.com/logos/foss_logo.png "GeoSol Research")](https://geosolresearch.com)

# Memoize (Class-Based Memoization)

Per-instance memoization for class methods with full type hint and docstring preservation.

## Overview

gri-memoize provides a `MemoizedClass` base class and a `@memoize` decorator for caching method results within class instances. Unlike `functools.lru_cache`, which stores results in a global cache tied to the function object, gri-memoize keeps cached results on each instance -- so garbage collection, per-instance invalidation, and IDE tooling all work as expected.

Requires Python 3.12+.

## Installation

```bash
pip install gri-memoize
```

For development:

```bash
git clone https://gitlab.com/geosol-foss/python/gri-memoize.git
cd gri-memoize
. .init_venv.sh
```

## Quick Start

```python
from gri_memoize import MemoizedClass, memoize


class Geometry(MemoizedClass):
    def __init__(self, radius: float):
        self._radius = radius

    @memoize
    def area(self) -> float:
        """Circle area (cached after first call)."""
        return 3.14159 * self._radius ** 2

    @memoize
    def circumference(self) -> float:
        """Circle circumference (cached after first call)."""
        return 2 * 3.14159 * self._radius


g = Geometry(5.0)
g.area()           # Computed
g.area()           # Returned from cache
g.clear_memoized_results()  # Invalidate all cached results
g.area()           # Recomputed
```

## Why Not `functools.lru_cache`?

| Feature | `lru_cache` | `gri-memoize` |
|---------|-------------|---------------|
| Cache scope | Global (per function) | Per instance |
| Garbage collection | Cache holds references, preventing GC | Cache dies with instance |
| Cache invalidation | `cache_clear()` clears all instances | `clear_memoized_results()` per instance |
| IDE support | Often loses docstrings and type hints in class context | Full `@wraps` preservation |
| Argument hashing | Uses `__hash__` on all args | Same, plus function name isolation |

## Usage

1. Inherit from `MemoizedClass`
2. Decorate methods with `@memoize`
3. Call `clear_memoized_results()` if the underlying data changes

```python
from gri_memoize import MemoizedClass, memoize


class Sensor(MemoizedClass):
    def __init__(self, readings: list[float]):
        self._readings = readings

    @memoize
    def mean(self) -> float:
        return sum(self._readings) / len(self._readings)

    @memoize
    def variance(self) -> float:
        m = self.mean()
        return sum((x - m) ** 2 for x in self._readings) / len(self._readings)

    def update(self, readings: list[float]) -> None:
        self._readings = readings
        self.clear_memoized_results()  # Invalidate stale cache
```

Methods with arguments are cached per unique argument combination:

```python
class Matrix(MemoizedClass):
    @memoize
    def power(self, n: int) -> float:
        return self._value ** n

m = Matrix()
m.power(2)  # Cached for n=2
m.power(3)  # Cached separately for n=3
```

## How It Works

Each `MemoizedClass` instance carries a `memoized_results` dictionary, initialized in `__new__` to support multiple inheritance. The `@memoize` decorator hashes the function name, positional args, and sorted keyword args into a key. On cache hit, the stored result is returned without calling the function.

## Dependencies

None. gri-memoize has no external dependencies.


## Other Projects

Current list of other [GRI FOSS Projects](https://gitlab.com/geosol-foss/python/gri-memoize/-/blob/main/.docs_other_projects.md) we are building and maintaining.

## License

MIT License. See [LICENSE](https://gitlab.com/geosol-foss/python/gri-memoize/-/blob/main/LICENSE) for details.
