Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Support for Flask Caching #151

Open
grantjenks opened this issue Jul 5, 2020 · 2 comments
Open

Add Support for Flask Caching #151

grantjenks opened this issue Jul 5, 2020 · 2 comments

Comments

@grantjenks
Copy link
Owner

Add support for Flask Caching. Details at https://flask-caching.readthedocs.io/en/latest/

@grantjenks
Copy link
Owner Author

Progress started in #154

@filak
Copy link

filak commented Jun 22, 2022

Thank you for a great library !

I have been using Diskcache with Flask for some time, but not with all the possible Flask-Caching features.

I have just subclassed the Cache class:

import functools as ft
from diskcache.core import args_to_key, full_name
from diskcache import Cache
from pathlib import Path
from flask import Flask

class DiskCache(Cache):
    def __init__(self, *args, **kwargs):
        Cache.__init__(self, *args, **kwargs)

    def init_app(self, app: Flask) -> None:
        directory  = app.config.get('CACHE_DIR')
        if not directory:
            raise ValueError(f"Missing CACHE_DIR setting")
        else:
            cpath = Path( directory )
            if not cpath.is_dir():
                raise ValueError(f"Invalid CACHE_DIR")    
        
        timeout = app.config.get('CACHE_DEFAULT_TIMEOUT', 3600)

        self.__init__(directory, timeout=timeout, statistics=True, tag_index=True)

    def set(self, key, value, expire=None, read=False, tag=None, retry=False, timeout=None):
        if not expire and timeout:
            expire = timeout

        super().set(key, value, expire=expire, read=read, tag=tag, retry=retry)             

    def memoize(self, name=None, typed=False, expire=None, tag=None, ignore=(), timeout=None):
        if not expire and timeout:
            expire = timeout  
  
        def decorator(func):
            base = (full_name(func),) if name is None else (name,)

            @ft.wraps(func)
            def wrapper(*args, **kwargs):
                key = wrapper.__cache_key__(*args, **kwargs)
                result = self.get(key, default='ENOVAL', retry=True)

                if result == 'ENOVAL':
                    result = func(*args, **kwargs)
                    if expire is None or expire > 0:
                        self.set(key, result, expire, tag=tag, retry=True)

                return result

            def __cache_key__(*args, **kwargs):
                return args_to_key(base, args, kwargs, typed, ignore)

            wrapper.__cache_key__ = __cache_key__
            return wrapper

        return decorator

What I miss in your Cache class is support for the Flask app factory pattern - cache.init_app(app) - which can be hacked ie with adding the init_later param:

 cache = DiskCache(init_later=True)
 cache.init_app(app)
class Cache:
    """Disk and file backed cache."""

    def __init__(self, directory=None, timeout=60, disk=Disk, **settings):
        """Initialize cache instance...
        """
        try:
            assert issubclass(disk, Disk)
        except (TypeError, AssertionError):
            raise ValueError('disk must subclass diskcache.Disk') from None

        if settings.get('init_later'):
            return
        ...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants