How do I cache a Flask view that returns an Image?

575 Views Asked by At

My function:

@app.route("/media/<collection>/<unique_path>/<path:filename>")
def view_media_file(collection, unique_path, filename):
    document = db.find_one_or_404(collection, 'unique_path', unique_path)
    hex_id = filename.rsplit(".", 1)[0]
    if not hex_id in document.get("files", {}).keys():
        return "Error", 404
    response_obj = app.mongo.send_file(filename)
    return response_obj

when I try Flask-Caching:

@app.route("/media/<collection>/<unique_path>/<path:filename>")
@cache.cached()
def view_media_file(collection, unique_path, filename):
    ...

I get a 500 error with the following traceback:

Traceback (most recent call last):
  File "...flask/env/lib/python3.9/site-packages/flask/app.py", line 2548, in __call__
    return self.wsgi_app(environ, start_response)
  File "...flask/env/lib/python3.9/site-packages/flask/app.py", line 2528, in wsgi_app
    response = self.handle_exception(e)
  File "...flask/env/lib/python3.9/site-packages/flask/app.py", line 2525, in wsgi_app
    response = self.full_dispatch_request()
  File "...flask/env/lib/python3.9/site-packages/flask/app.py", line 1822, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "...flask/env/lib/python3.9/site-packages/flask/app.py", line 1820, in full_dispatch_request
    rv = self.dispatch_request()
  File "...flask/env/lib/python3.9/site-packages/flask/app.py", line 1796, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
  File "...flask/env/lib/python3.9/site-packages/flask_caching/__init__.py", line 413, in decorated_function
    self.cache.set(
  File "...flask/env/lib/python3.9/site-packages/cachelib/simple.py", line 80, in set
    self._cache[key] = (expires, self.serializer.dumps(value))
  File "...flask/env/lib/python3.9/site-packages/cachelib/serializers.py", line 43, in dumps
    serialized = pickle.dumps(value, protocol)
TypeError: cannot pickle '_thread.lock' object

How do I serialize (dumps/loads) a pymongo response object that is a file?

I've tried this with cached and memoized, and I've tried to serialize with json and pickle modules. I understand that thread locking is the issue in the traceback, but I'm not very familiar with it, and don't really understand why it applies to this type of file response delivery, but not with a standard response.

Python 3.10.1

Flask==2.2.2

Flask-Caching==2.0.1

full response_obj:

object: <Response streamed [200 OK]>
type(object): <class 'flask.wrappers.Response'>

response_obj attributes:

<Response streamed [200 OK]>.accept_ranges: None
<Response streamed [200 OK]>.access_control_allow_credentials: False
<Response streamed [200 OK]>.access_control_allow_headers: None
<Response streamed [200 OK]>.access_control_allow_methods: None
<Response streamed [200 OK]>.access_control_allow_origin: None
<Response streamed [200 OK]>.access_control_expose_headers: None
<Response streamed [200 OK]>.access_control_max_age: None
<Response streamed [200 OK]>.add_etag: <bound method Response.add_etag of <Response streamed [200 OK]>>
<Response streamed [200 OK]>.age: None
<Response streamed [200 OK]>.allow: 
<Response streamed [200 OK]>.autocorrect_location_header: False
<Response streamed [200 OK]>.automatically_set_content_length: True
<Response streamed [200 OK]>.cache_control: max-age=31536000, public
<Response streamed [200 OK]>.calculate_content_length: <bound method Response.calculate_content_length of <Response streamed [200 OK]>>
<Response streamed [200 OK]>.call_on_close: <bound method Response.call_on_close of <Response streamed [200 OK]>>
<Response streamed [200 OK]>.charset: utf-8
<Response streamed [200 OK]>.close: <bound method Response.close of <Response streamed [200 OK]>>
<Response streamed [200 OK]>.content_encoding: None
<Response streamed [200 OK]>.content_language: 
<Response streamed [200 OK]>.content_length: 2924675
<Response streamed [200 OK]>.content_location: None
<Response streamed [200 OK]>.content_md5: None
<Response streamed [200 OK]>.content_range: 
<Response streamed [200 OK]>.content_security_policy: 
<Response streamed [200 OK]>.content_security_policy_report_only: 
<Response streamed [200 OK]>.content_type: image/png
<Response streamed [200 OK]>.cross_origin_embedder_policy: COEP.UNSAFE_NONE
<Response streamed [200 OK]>.cross_origin_opener_policy: COOP.UNSAFE_NONE
0

There are 0 best solutions below