5

In order to cache some data, I am calling cache.set method. However it is throwing KeyError. The error log:

 File "D:\Sample_Project\SomeRouter.py", line 176, in run
    FetchFeed._prepareCache(f_content, cache, _program, _sprint)
  File "D:\Sample_Project\SomeRouter.py", line 197, in _prepareCache
    cache.set(cKey, data[last_index:last_index + MAX_DATA_PER_PAGE])
  File "c:\python\lib\site-packages\flask_caching\__init__.py", line 254, in set
    return self.cache.set(*args, **kwargs)
  File "c:\python\lib\site-packages\flask_caching\__init__.py", line 246, in cache
    return app.extensions["cache"][self]
KeyError: <flask_caching.Cache object at 0x04F9C8D0>

The server module looks like :

cache_type = 'simple' if 'FLASK_ENV' in os.environ and os.environ['FLASK_ENV'] == 'development' else 'uwsgi'
cache = Cache(config={'CACHE_TYPE': cache_type})
app = Flask("MY_PROJECT")
cache.init_app(app)

# some api.route functions
# goes here ....

if __name__ == "__main__":
    with app.app_context():
        cache.clear()
    app.run(host="0.0.0.0")

And SomeRouter module:

from server import cache

@staticmethod
def _prepareCache(data, cache, program):
    total_records = len(data)
    if total_records > 0:
        cKey = FetchFeed \
            ._constructCacheKey(program)
        cache.set(cKey, data)
    else:
        print("data size is empty.")

Note: I have removed unnecessary codes.

I also put breakpoints, and called cache.set(some_key, some_value) in server module itself. It is returning True, but same cache object is throwing KeyError when imported and used in SomeRouter module. Can it be that the way I am importing an object is wrong? I also tried importing the cache object right before using it, but it did not work. Any idea what is going on here?

TheLittleNaruto
  • 8,325
  • 4
  • 54
  • 73
  • Looking at [the source](https://github.com/sh4nks/flask-caching/blob/b8e2fa6d3251dc60548751855d1d329eecef132a/flask_caching/__init__.py#L236) it seems `Cache.cache` looks itself up first in `current_app` or, if no app is running, the `self.app` attribute which is just the last app on which `Cache.init_app` as called. So it seems any time a new app context is created you need to call `cache.init_app` on it. – Iguananaut Jan 10 '20 at 10:17
  • @Iguananaut Do you mean I should call `init_app` when I am starting the server i.e. prior of calling `app.run()` so that it'll get the correct context ? – TheLittleNaruto Jan 10 '20 at 10:27
  • I think so; admittedly it is not entirely clear to me either, and neither is the documentation. But yes, that seems to be the case. You should call init_app when running the server, rather than at module-level – Iguananaut Jan 10 '20 at 10:32
  • @Iguananaut I wonder why would that work if called in same module i.e. server module where it's get initialized and init_app'ed as I told in my question? Also that did not work, tried just now. – TheLittleNaruto Jan 10 '20 at 10:34
  • It might be useful to see exactly how you are using `_prepareCache`. As it is your example is not reproducible. – Iguananaut Jan 10 '20 at 13:57
  • @Iguananaut That's just concatenation of strings. Leave that aside, even if I do `cache.set("hello","world")` it throws same error. – TheLittleNaruto Jan 10 '20 at 15:28
  • Yes of course. If you look at the code for the cache module it's clear why. But the example code you gave is incomplete so it's impossible to reproduce the problem. Please supply a complete example that reproduces the problem. – Iguananaut Jan 12 '20 at 14:57
  • @Iguananaut I am outside atm. Will share after reaching. Could you help me "why" would not that work? I looked into source code and was unable to understand. – TheLittleNaruto Jan 12 '20 at 15:40
  • I pointed to the relevant code in my first comment. You can't use the cache until it's been initialized in the current app context. – Iguananaut Jan 12 '20 at 23:34

1 Answers1

3

The problem was I was accessing cache object outside request context i.e. in "SomeRouter" module, and because of which it was unaware that under which context it is been used.

In server module where request has been received, the cache knows about the app application, but during cache.set(cKey, data) in SomeRouter module, it throws KeyError. This error is justified as mentioned above.

The resolution is to push the application context as below:

from server import app, cache

# Using context
with app.app_context():
    cache.set(cKey, data)

This will push a new application context (using the application of app).

All thanks to Mark Hildreth, for his great answer on context in flask

TheLittleNaruto
  • 8,325
  • 4
  • 54
  • 73
  • well, could explain your answer please? I have the same issue but I don't really understand this ad don't know how do I suppose to apply this in my app, Perhaps you could update my ticket here: https://stackoverflow.com/questions/64449841/flask-cache-throws-error-keyerror-flask-caching-cache-object-at-0x7ff585e473 – smoczyna Oct 22 '20 at 18:44