Forums

flask send_file() return SystemError

Hi, I'm trying to return files as bytes from database using send_file() and i got 500 Internal Error. Below is my code:

return send_file(BytesIO(dec_data), mimetype=cipherfile.file_type, as_attachment=True,
                          attachment_filename=cipherfile.filename)

and this from error.log:

2018-07-24 12:04:46,875: [2018-07-24 12:04:46,825] ERROR in app: Exception on /decrypt/4 [POST]
2018-07-24 12:04:46,876: io.UnsupportedOperation: fileno
2018-07-24 12:04:46,876: 
2018-07-24 12:04:46,876: The above exception was the direct cause of the following exception:
2018-07-24 12:04:46,876: 
2018-07-24 12:04:46,876: Traceback (most recent call last):
2018-07-24 12:04:46,877:   File "/home/ac78/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/app.py", line 2292, in wsgi_app
2018-07-24 12:04:46,877:     response = self.full_dispatch_request()
2018-07-24 12:04:46,877:   File "/home/ac78/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/app.py", line 1815, in full_dispatch_request
2018-07-24 12:04:46,877:     rv = self.handle_user_exception(e)
2018-07-24 12:04:46,877:   File "/home/ac78/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/app.py", line 1718, in handle_user_exception
2018-07-24 12:04:46,878:     reraise(exc_type, exc_value, tb)
2018-07-24 12:04:46,878:   File "/home/ac78/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/_compat.py", line 35, in reraise
2018-07-24 12:04:46,878:     raise value
2018-07-24 12:04:46,878:   File "/home/ac78/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/app.py", line 1813, in full_dispatch_request
2018-07-24 12:04:46,879:     rv = self.dispatch_request()
2018-07-24 12:04:46,879:   File "/home/ac78/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/app.py", line 1799, in dispatch_request
2018-07-24 12:04:46,879:     return self.view_functions[rule.endpoint](**req.view_args)
2018-07-24 12:04:46,879:   File "/home/ac78/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask_login/utils.py", line 261, in decorated_view
2018-07-24 12:04:46,879:     return func(*args, **kwargs)
2018-07-24 12:04:46,879:   File "/home/ac78/kripto/app/auth/decorators.py", line 13, in decorated_function
2018-07-24 12:04:46,879:     return func(*args, **kwargs)
2018-07-24 12:04:46,880:   File "/home/ac78/kripto/app/main/routes.py", line 129, in decrypt
2018-07-24 12:04:46,880:     attachment_filename=cipherfile.filename)
2018-07-24 12:04:46,880:   File "/home/ac78/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/helpers.py", line 592, in send_file
2018-07-24 12:04:46,880:     data = wrap_file(request.environ, file)
2018-07-24 12:04:46,880:   File "/home/ac78/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/werkzeug/wsgi.py", line 893, in wrap_file
2018-07-24 12:04:46,880:     return environ.get('wsgi.file_wrapper', FileWrapper)(file, buffer_size)
2018-07-24 12:04:46,881: SystemError: <built-in function uwsgi_sendfile> returned a result with an error set
2018-07-24 12:04:46,825: Exception on /decrypt/4 [POST]#012io.UnsupportedOperation: fileno#012#012The above exception was the direct cause of the following exception:#012#012Traceback (most recent call last):#012  File "/home/ac78/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/app.py", line 2292, in wsgi_app#012    response = self.full_dispatch_request()#012  File "/home/ac78/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/app.py", line 1815, in full_dispatch_request#012    rv = self.handle_user_exception(e)#012  File "/home/ac78/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/app.py", line 1718, in handle_user_exception#012    reraise(exc_type, exc_value, tb)#012  File "/home/ac78/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/_compat.py", line 35, in reraise#012    raise value#012  File "/home/ac78/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/app.py", line 1813, in full_dispatch_request#012    rv = self.dispatch_request()#012  File "/home/ac78/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/app.py", line 1799, in dispatch_request#012    return self.view_functions[rule.endpoint](**req.view_args)#012  File "/home/ac78/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask_login/utils.py", line 261, in decorated_view#012    return func(*args, **kwargs)#012  File "/home/ac78/kripto/app/auth/decorators.py", line 13, in decorated_function#012    return func(*args, **kwargs)#012  File "/home/ac78/kripto/app/main/routes.py", line 129, in decrypt#012    attachment_filename=cipherfile.filename)#012  File "/home/ac78/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/flask/helpers.py", line 592, in send_file#012    data = wrap_file(request.environ, file)#012  File "/home/ac78/.virtualenvs/my-virtualenv/lib/python3.6/site-packages/werkzeug/wsgi.py", line 893, in wrap_file#012    return environ.get('wsgi.file_wrapper', FileWrapper)(file, buffer_size)#012SystemError: <built-in function uwsgi_sendfile> returned a result with an error set

BytesIO is not a filename or a file pointer, which is what send_file requires as its first argument.

We have written a help page to help with this in future http://help.pythonanywhere.com/pages/FlaskSendFileBytesIO/

Thanks. I looked at the help page, and I'm wondering how, using this method, I might specify a filename for the Response object? Google has failed me so far.

this?

Thanks for the quick reply and sorry to be so slow, but...

Yes, based on that page I did try response.headers["x-suggested-filename"] and response.headers["x-filename"], none of which seem to do anything for me.

My code looks like:

mem = io.BytesIO()
# here stuff happens to mem
response = Response(FileWrapper(mem), mimetype="application/zip", direct_passthrough=True)
response.headers["x-filename"] = 'results.zip'
response.headers["Access-Control-Expose-Headers"] = 'x-filename'
return response

Is there something obvious I'm missing here?

Update: I first solved my problem based on https://stackoverflow.com/questions/43365640/set-unicode-filename-in-flask-response-header:

response.headers['Content-Disposition'] = 'attachment; filename=results.zip'

And then I found this other pythonanywhere topic: https://www.pythonanywhere.com/forums/topic/13570/. So my Google-fu is indeed weak.

May I suggest that the filename instructions could be added to http://help.pythonanywhere.com/pages/FlaskSendFileBytesIO/?

Thanks again for helping out.