79574566

Date: 2025-04-15 07:22:12
Score: 0.5
Natty:
Report link

I wanted to have something from the Python standard library like shelve, but also the parameters from cachier. So I built upon the answer of @nehem and @thegreendroid.

import datetime
import os
import shelve
import pickle
from functools import wraps

def shelve_it(cache_dir='/tmp/cache', stale_after=None):
    '''
    A decorator to cache the results of a function.

    Args:
    - cache_dir (str): The directory where the cache will be stored.
    - stale_after (timedelta): The duration after which the cache is considered stale.
    '''
    cache_file = os.path.join(cache_dir, 'cache.shelve')

    if not os.path.exists(cache_dir):
        os.makedirs(cache_dir)

    def decorator(func):
        @wraps(func)
        def new_func(*args, **kwargs):
            cache_key = pickle.dumps((args, kwargs))
            cache_key_str = cache_key.hex()

            with shelve.open(cache_file) as d:
                if cache_key_str in d:
                    if stale_after and 'timestamp' in d[cache_key_str]:
                        timestamp = d[cache_key_str]['timestamp']
                        if datetime.datetime.now() - timestamp > stale_after:
                            del d[cache_key_str]
                            print(f'Cache for {cache_key_str} is stale, recalculating...')
                        else:
                            return d[cache_key_str]['result']
                    else:
                        return d[cache_key_str]

                result = func(*args, **kwargs)

                if stale_after:
                    d[cache_key_str] = {'result': result, 'timestamp': datetime.datetime.now()}
                else:
                    d[cache_key_str] = result
                    
                return result

        return new_func

    return decorator

Usage

@shelve_it(cache_dir='/tmp/my_cache', stale_after=datetime.timedelta(days=2))
def expensive_function(param, multiplier=2):
    import time
    time.sleep(2)
    return param * multiplier

print(expensive_function('test'))  # This will take 2 seconds
print(expensive_function('test'))  # This will be instant, using the cache
Reasons:
  • Long answer (-1):
  • Has code block (-0.5):
  • User mentioned (1): @nehem
  • Low reputation (1):
Posted by: Speech-To-Text.Cloud