1

I'm working with Python 3. Here is the part that sets up the response for file download -

import io
import pandas as pd
@app.route('/download_log',methods=['GET'])
def download_log():
   output = io.BytesIO() 
   writer = pd.ExcelWriter(output, engine='xlsxwriter')
   # s is a Pandas Dataframe that I want to have downloaded as an excel
   s.to_excel(writer, sheet_name='Sheet1')
   writer.save()
   output.seek(0)
   excelDownload=output.read()
   return send_file(excelDownload,attachment_filename='log.xlsx',as_attachment=True)

My main goal is that I need to make the contents of the dataframe(in this case 's') available as an xlsx download to the client and I do not want to save this file on the server (I have tried it and it works); I want to be able to do this on the fly. For this pandas only allows me to use io.BytesIO as input to ExcelWriter. The value in the DataFrame are actual strings but when I print excelDownload I get values of the form(This is just the first line)

 b'PK\x03\x04\x14\x00\x00\x00\x08\x00\xf5c9J,)\xbdS\x13\x01\x00\x00\xc6\x01\x00\x

I am not sure if this is the source of my problems, but the xlsx gets downloaded at the client can't be opened; I get the error 'File can't be opened because file format or file extension may be invalid'. Do I need to decode the Byte stream before sending it as a response; if I do, which codec do I use? utf-8, latin-1 etc don't seem to be working. Also, I get the error - " Debugging middleware caught exception in streamed response at a point where response headers were already sent " in my console. I guess its because of the format of file I'm sending(excelDownload) How do I get all the details of the dataframe properly reproduced in the downloaded excel? I've spent a dozen hours on this and would be extremely grateful for any pointers

Bellerofont
  • 1,081
  • 18
  • 17
  • 16
Savvy
  • 547
  • 5
  • 12
  • 1
    Looks like the beginning of a zipfile to me. You can actually send it as `send_file(output)` I'm pretty sure. Have you verified that you are actually generating an excel file, i.e. you take the code that generates the file and you write it to disk, then open *that* in Excel? Finally, you don't *quite* have a [mcve] here, which you could easily turn this into by adding a few dummy lines to your pandas dataframe. – Wayne Werner Jan 27 '17 at 19:12
  • xlsx files are zipfiles, so `send_file(output, attachment_filename='log.xlsx',as_attachment=True)` should work correctly. You will still need `output.seek(0)`. – cco Jan 27 '17 at 21:47
  • @WayneWerner you were right ! I had a misconception about manipulating Global variables. The 's' in s.to_excel() was being set outside download_log() method. I did not know that to assign a value to a global variable I would have to explicitly refer the scope by writing the line - 'global s' . I don't remember having to do anything like this in plain python. I guess this is characteristic to Flask. Perhaps you could type out your suggestion as an answer and I can accept it. After all if it weren't for your suggestion I wouldn't have thought of printing 's' (which is kinda embarrassing btw !!) – Savvy Feb 01 '17 at 13:13
  • You shouldn't have to explicitly state `global s` unless you're re-assigning to `s`. That being said, one letter variable names are terrible and you *probably* shouldn't be using globals, either. Honestly I'd just delete this question if I were you - the problem was a typo, so it's not really likely to help anyone in the future, unless they make the same sort of typo. – Wayne Werner Feb 01 '17 at 14:17

0 Answers0