Skip to content

pmrv/fleche

Repository files navigation

fleche

docs

A persistent caching solution for arbitrary Python functions - like lru_cache on steroids.

flèche is French for 'arrow' and also used in fencing as a fast attack.

Features

  • Persistent Caching: Cache function results across runs using various storage backends
  • Flexible Storage: Choose from file-based, SQL, in-memory, or custom storage solutions
  • Intelligent Hashing: Automatically generates cache keys from function arguments
  • Query Support: Search and retrieve cached results with metadata filtering
  • Configurable: Control what gets hashed (version, module, code, arguments)
  • Multiple Backends: File (pickle, cloudpickle, dill), SQLAlchemy, Bagofholding, and more
  • Thread-Safe: Safe for use in multi-threaded environments
  • Type-Aware: Works seamlessly with NumPy, Pandas, and custom types

Installation

Basic Installation

pip install fleche

With conda

fleche is available on conda-forge. Two packages are published:

  • fleche-base — the core library only (no optional dependencies)
  • fleche — the full install, which also pulls in the optional dependencies (cloudpickle, dill, sqlalchemy, and bagofholding), enabling the SQL, SSH, alternate-serialization, and Bagofholding features out of the box
# Core library only
conda install -c conda-forge fleche-base

# Full install with all optional dependencies
conda install -c conda-forge fleche

With Optional Dependencies

# For SQL storage
pip install fleche[sqlalchemy]

# For alternate serialization formats
pip install fleche[cloudpickle,dill]

# For Bagofholding storage
pip install fleche[bagofholding]

# For SshCache (sharing caches across machines over SSH) — requires cloudpickle
pip install fleche[ssh]

# For running cached calls through executorlib executors
pip install fleche[executorlib]

# For documentation
pip install fleche[docs]

# For development and testing
pip install fleche[tests]

See the Optional dependencies section of the docs for a full table of extras and the features they enable.

Quick Start

Basic Usage

from fleche import fleche

@fleche()
def expensive_function(x, y):
    """This function's results will be cached."""
    print(f"Computing for {x}, {y}...")
    return x + y

# First call computes the result
result = expensive_function(1, 2)  # prints "Computing for 1, 2..."

# Second call retrieves from cache
result = expensive_function(1, 2)  # no print - result from cache!

# Different arguments compute again
result = expensive_function(2, 3)  # prints "Computing for 2, 3..."

Working with Cache Results

@fleche()
def compute(x):
    return x ** 2

# Get the cache key (digest) for arguments
digest = compute.digest(5)

# Check if result is cached
if compute.contains(5):
    result = compute.load(5)
else:
    result = compute(5)

# Get Call object with metadata
call = compute.call(5)

Configuration

Decorator Options

@fleche(
    version=1,           # Versioning for function changes
    hash_version=True,   # Include version in cache key
    hash_module=True,    # Include module name in cache key
    hash_code=False,     # Include function code in cache key
    require=None,        # Required argument for caching
    ignore=None,         # Arguments to ignore in cache key
)
def my_function(x):
    return x * 2

Storage Backends

In-Memory Storage (Default)

  • Default when no fleche.toml configuration file is present
  • Transient: data is lost when the process exits

File Storage

  • Stores cache in filesystem using pickle (or cloudpickle/dill)
  • Persistent across runs
  • XDG Base Directory Specification compliant when configured

SQL Storage

  • Requires sqlalchemy
  • Call storage only — stores call records (function name, arguments, metadata) in a SQL database; a separate value backend (file or memory) is still required for results
  • SQLite is the primary tested backend; any SQLAlchemy-supported database should work
  • Enables efficient server-side filtering when querying cached calls

SSH (remote) Cache

  • Requires cloudpickle (pip install fleche[ssh]) — used as the wire protocol between client and remote server; not optional
  • Forwards every cache operation over a persistent ssh host python -m fleche remote --serve subprocess
  • Stack with a local cache to read-through to a shared remote one — see fleche.remote.SshCache

Custom Backends

Implement the Storage interface to create custom backends.

Advanced Features

Versioning

Track function versions to invalidate cache when implementation changes:

@fleche(version=2)
def process_data(data):
    # Incrementing version invalidates all v1 cache entries
    return data * 2

Ignoring Arguments

Skip certain arguments when generating cache keys:

@fleche(ignore=['verbose', 'debug'])
def compute(x, y, verbose=False, debug=False):
    return x + y  # Cache key only uses x and y

Querying Results

Find cached results matching specific criteria (only after issuing a corresponding call):

@fleche()
def fetch_data(user_id, date):
    return {"user": user_id, "date": date}

# Issue a call to cache the result
fetch_data(user_id=123, date='2024-01-01')

# Get all cached results for fetch_data
all_results = list(fetch_data.query())

# Get results where user_id=123, any date (omitted arguments act as wildcards)
results = list(fetch_data.query(user_id=123))

# Inspect a result
for call in fetch_data.query(user_id=123):
    print(call.arguments, call.result)

Performance

Use the included benchmarks to evaluate performance:

python -m benchmarks.run_benchmarks

Testing

Run the test suite:

pip install "fleche[tests]"
pytest tests/

Contributing

Contributions are welcome! Please ensure tests pass and code follows the project style.

License

BSD-3-Clause License - see LICENSE file for details.

Resources

  • Documentation: See docs/ directory
  • Tests: See tests/ for usage examples
  • Benchmarks: See benchmarks/ for performance metrics

About

Hierachical, persistant caches in python

Resources

Stars

Watchers

Forks

Releases

Packages

Used by

Contributors

Languages