Python Flask send_file StringIO blank files

Question:

I want to process a Pandas dataframe and send it to download as a CSV without a temp file. The best way to accomplish this I’ve seen is to use StringIO. Using the code below, a file downloads with the proper name, however the file is completely blank, and no error is shown. Why doesn’t the file contain data?

@app.route('/test_download', methods = ['POST'])
def test_download():
    buffer = StringIO()
    buffer.write('Just some letters.')
    buffer.seek(0)
    return send_file(
        buffer,
        as_attachment=True,
        download_name='a_file.txt',
        mimetype='text/csv'
    )
Asked By: Daniel Hitchcock

||

Answers:

Use BytesIO to write bytes.

from io import BytesIO
from flask import Flask, send_file

app = Flask(__name__)

@app.route('/test_download', methods=['POST'])
def test_download():
    # Use BytesIO instead of StringIO here.
    buffer = BytesIO()
    buffer.write(b'Just some letters.')
    # Or you can encode it to bytes.
    # buffer.write('Just some letters.'.encode('utf-8'))
    buffer.seek(0)
    return send_file(
        buffer,
        as_attachment=True,
        download_name='a_file.txt',
        mimetype='text/csv'
    )

Prior to Flask 2.0, download_name was called attachment_filename.

Answered By: lord63. j

if someone use python 2.7 with Flask and got the error about the module StringIO by importing it. This post can help you to solve your problem.

If you are importing String IO module, you can just change the import syntax by using this : from io import StringIO instead from StringIO import StringIO.

You can Also use from io import BytesIO if you are using image or some others ressource.

Thank you

Answered By: Lamine BA

The issue here is that in Python 3 you need to use StringIO with csv.write and send_file requires BytesIO, so you have to do both.

@app.route('/test_download')
def test_download():
    row = ['hello', 'world']
    proxy = io.StringIO()
    
    writer = csv.writer(proxy)
    writer.writerow(row)
    
    # Creating the byteIO object from the StringIO Object
    mem = io.BytesIO()
    mem.write(proxy.getvalue().encode())
    # seeking was necessary. Python 3.5.2, Flask 0.12.2
    mem.seek(0)
    proxy.close()

    return send_file(
        mem,
        as_attachment=True,
        download_name='test.csv',
        mimetype='text/csv'
    )

Prior to Flask 2.0, download_name was called attachment_filename.

Answered By: Radu

make_response

  • To get Flask to download a csv file to the user, we pass a csv string to the make_response function, which returns a
    Response object.
  • Then we add a Header which tells the browser to accept the file as a download.
  • The Mimetype also must be set to text/csv in order to get the web browser to save it in something other than an html document.
from flask import Flask, make_response  
app = Flask(__name__)

@app.route('/test_download', methods=['POST'])
def test_download():
    with StringIO() as buffer:
        # forming a StringIO object  
        buffer = StringIO()
        buffer.write('Just some letters.')
        # forming a Response object with Headers to return from flask 
        response = make_response(buffer.getvalue())
        response.headers['Content-Disposition'] = 'attachment; filename=namaste.csv'
        response.mimetype = 'text/csv'
        # return the Response object
        return response

P.S. It is preferred to use python’s built-in csv library to deal with csv files

References

Namaste

Answered By: Deepam Gupta
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.