jmcnamara / XlsxWriter

A Python module for creating Excel XLSX files.
https://xlsxwriter.readthedocs.io
BSD 2-Clause "Simplified" License
3.65k stars 633 forks source link

Bug: The file is corrupt and therefore cannot be opened #1051

Closed laurent-brisbois closed 8 months ago

laurent-brisbois commented 8 months ago

Current behavior

Simple example, I try to generate the file with example first to see if it works but it doesn't, see below :

image image image image

Expected behavior

I'd like to be able to at least generate the sample from the docs.

Sample code to reproduce

import xlsxwriter
from io import BytesIO
output = BytesIO()
workbook = xlsxwriter.Workbook(output, {"in_memory": True})
worksheet = workbook.add_worksheet()
data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
for row_num, columns in enumerate(data):
    for col_num, cell_data in enumerate(columns):
        worksheet.write(row_num, col_num, cell_data)
workbook.close()
output.seek(0)
response = HttpResponse(  # This is django.http.HttpResponse
    output,
    content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
)
response["Content-Disposition"] = "attachment; filename=othertest2.xlsx"
return response

Environment

- XlsxWriter version: 3.2.0
- Python version: 3.8.13
- Excel version: (LibreOffice) 7.6
- OS: Ubuntu 20.04

Any other information

I don't think it's a matter of returning the file correctly because I'm able to download images or CSV files with another endpoints. This is from a personal project and given example doesn't work. In another project I used once, there was xlsxwriter==1.4.3 with lots of formattings and so on and it works on the same computer.

OpenOffice and LibreOffice users

jmcnamara commented 8 months ago

A few questions:

  1. The sample code isn't complete. Could you update it with a complete working program?
  2. What happens when you run the example exactly as it is in the docs/repo?
  3. Are you streaming the file directly to LibreOffice:
    • If yes what happens if you just download the file and then open it in LibreOffice
  4. Are you creating the xlsx file on one system and then transferring it to another machine where one of the machines is Windows based.
    • If so are you transferring the file in binary mode.
  5. The third screenshot shows that Libreoffice thinks that the file is a text file. Did this happen automatically or were you trying to load the file manually? (Btw, the file starts with PK which indicates that it is a zip/xlsx file which is correct.)
laurent-brisbois commented 8 months ago

Hello !

Thank you for your first answer.

  1. Here is "complete" code, you'll still have to have a basic app with Django and DjangRestFramework :

I removed authentication_classes and permission_classes on purpose here.

from io import BytesIO

import xlsxwriter
from django.http import HttpResponse  # Or use rest_framework.response.Response
from rest_framework.decorators import api_view
from rest_framework.request import Request

@api_view(http_method_names=["GET"])
def export_xlsx(request: Request):
    output = BytesIO()
    workbook = xlsxwriter.Workbook(output, {"in_memory": True})
    data = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    for row_num, columns in enumerate(data):
        for col_num, cell_data in enumerate(columns):
            worksheet.write(row_num, col_num, cell_data)
    workbook.close()
    output.seek(0)
    response = HttpResponse(
        content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
    )
    response["Content-Disposition"] = "attachment; filename=othertest2.xlsx"
    return response
  1. This is example from the docs, but just used into an api_view from rest_framework.
  2. No, I download it and try to open it (double click, it tries to open it with LibreOffice, and you know the rest).
  3. My Django backend is running into a docker container (docker-compose, vuejs frontend, django backend). Once generated and downloaded, I try to open it on my Ubuntu 20.04 (or 22.04, I have both) machine and it doesn't work (corrupted xlsx file).
  4. It happens automatically. I just double clicked the xlsx file that I downloaded and it does that.

Note that I also tried to import the file in Google Sheet and it loads forever, I guess it cannot open it either.

Thank you for your help !

jmcnamara commented 8 months ago

For item 2 could you run the doc example, unedited, from the command line and let me know if it works.

laurent-brisbois commented 8 months ago

I installed xlsxwriter on my local machine (Ubuntu 22.04) widely like so :

$ sudo apt install python3-xlsxwriter

image

Not sure it is the 3.2.0 version though.. Seems like it is 3.0.2

then in python3 directly in my terminal (it worked) :

image image

My system python is 3.11.6 whereas in my docker container it is 3.8.13 but I don't think it's the problem here.

laurent-brisbois commented 8 months ago

Also I tried to run the exact same example for Django as in the docs : image but still the same : image

jmcnamara commented 8 months ago

Also I tried to run the exact same example for Django as in the docs : but still the same :

Could you attach the output file django_simple.xlsx to this GitHub issue.

laurent-brisbois commented 8 months ago

Could you attach the output file django_simple.xlsx to this GitHub issue.

Sure, here it is :

django_simple.xlsx

laurent-brisbois commented 8 months ago

Okay I found the issue and I have to say... my bad on this.

I use Axios for making queries between my vuejs frontend and my django backend. And whereas I already did file download in the past, I was considering it should work and that the issue couldn't come from there. But I completely forgot to set my responseType as blob for this new API service call in my frontend...

Thank you anyway for your reactivity, answers, and your willingness to help :ok_hand: :pray: .

laurent-brisbois commented 8 months ago

Maybe it is worth to be mentioned though in examples that show API endpoints.

jmcnamara commented 8 months ago

But I completely forgot to set my responseType as blob for this new API service call in my frontend...

No worries. I was zeroing in on the fact that the binary file had been treated as a text file someplace and "\n" had been replaced with "\r\n" or similar.

I will close it. Thanks for the followup.