Search code examples
pythonflaskcachingpython-decoratorsflask-caching

How to use use flask-caching decorator @cache on an external module class


Context: I have flask application, which is an NGINX authentication module, written in flask, and in some part of the code I am making a call to an LDAP server.

The objective is to use flask-caching library to cache the response from the LDAP server and avoid that costly call.

The code bellow its a very stripped down version showing only the relevant sections.

Problem In the below scenario I can't use the decorator @cache.memoized on a method of the Ldap class, as the variable cache is not available in that module.

name 'cache' is not defined

main.py

from flask import Flask  
from flask_caching import Cache
from ldap import Ldap

app = Flask(__name__)
cache = Cache(app)

@app.route('/', defaults={'path': ''})
@app.route('/<path:path>')
@auth.login_required
def index(path):
    code = 200
    msg = "Another LDAP Auth"
    headers = [('x-username', getRegister('username')),
               ('x-groups', getRegister('matchedGroups'))]
    return msg, code, headers

@auth.verify_password
def login(username, password):
    ldap = Ldap()
    ldap.verifyUser(username, password)

ldap.py

class Ldap: 
    @cache.memoized(timeout=300)            <<<< error 
    def validateUser(self, username, password)
        if <ldap query goes here>
            return True
        return False

Research The weird thing for me here is that this decorator depends on an object instance and not on a class as so many other scenarios I've seen

Alternative: Definitively if I put the definition of the class in the same main.py and bellow the definition of the cache variable it works, however this will make my main.py file too long.

Attempt 1: Trying to import my module after the definition of the cache variable has the same error

Attempt 2: doing from main import cache inside ldap.py creates a circular import error.

Idea: Pass the cache variable to the Ldap Class constructor and "somehow" use it to decorate the method, but I could not find how to do it exactly.


Solution

  • The solution is to initialize the cache in a different file, as described here.

    # cache.py
    from flask_caching import Cache
    cache = Cache()
    
    # main.py
    from flask import Flask 
    from cache import cache
    config = {
        "DEBUG": True,         
        "CACHE_TYPE": "filesystem",
        "CACHE_DIR": "flask_cache"
    }
    app = Flask(__name__)
    cache.init_app(app, config=config)
    
    # other.py
    from main import cache
    @cache.memoize(50)
    def some_func(abc):
        # do stuff