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: XlsxWriter creating xlsx file from IDE, but not when compiled #888

Closed RandallWert closed 2 years ago

RandallWert commented 2 years ago

Current behavior

I am using XlsxWriter (version 3.0.3) in my Python 3.9 program to create an xlsx file. This works perfectly as intended when I run my program from the IDE (IDLE). But when I compile my program with py2app, although the compilation seems to run without problems and the compiled app runs correctly otherwise, the compiled app does not produce any xlsx file.

Based on what I read at stackoverflow, I have already tried specifying the full filepath instead of just the filename, but the behavior remains the same.

Expected behavior

The compiled app should produce the desired xlsx file, just as it does before compilation when executed from the IDE.

Sample code to reproduce

# At top of code
import xlsxwriter

# Function for writing output to file
def write_file_output(file_output_dict):
    # Do the "meta" stuff that pertains to the whole spreadsheet (including the top rows of it)
    current_datetime = datetime.now()
    str_current_datetime = str(current_datetime)
    str_year = str_current_datetime[0:4]
    str_month = str_current_datetime[5:7]
    str_day = str_current_datetime[8:10]
    str_hour = str_current_datetime[11:13]
    str_min = str_current_datetime[14:16]
    str_sec = str_current_datetime[17:19]
    cwd = os.getcwd()
    filename = cwd + "/" + str_year + str_month + str_day + str_hour + str_min + str_sec + ".xlsx"
    workbook = xlsxwriter.Workbook(filename)
    worksheet = workbook.add_worksheet()
    worksheet.write('B1', 'Trial 1')
    worksheet.write('C1', 'Trial 2')
    worksheet.write('D1', 'Trial 3')
    # omitting many similar lines for brevity
    worksheet.write('N2', 'vj')

    # Create the rows for each of the stimuli
    row = 1
    for stimulus in file_output_dict:
        # Parse value for stimulus (key) file_output_dict into separate lists/variables
        f_o_hex_list = file_output_dict[stimulus][0]
        f_o_t1_rgb = file_output_dict[stimulus][1]
        f_o_t2_rgb = file_output_dict[stimulus][2]
        f_o_t3_rgb = file_output_dict[stimulus][3]
        vj = file_output_dict[stimulus][4]

        # Write the data to the row for this stimulus
        row += 1

        worksheet.write(row, 0, stimulus)

        cell_format = workbook.add_format()
        cell_format.set_pattern(1)
        if len(f_o_hex_list[0]) > 0:
            cell_format.set_bg_color(f_o_hex_list[0])
            worksheet.write(row, 1, '', cell_format)
        else:
            worksheet.write(row, 1, 'X')

        if len(f_o_hex_list[1]) > 0:
            cell_format.set_bg_color(f_o_hex_list[1])
            worksheet.write(row, 2, '', cell_format)
        else:
            worksheet.write(row, 2, 'X')

        if len(f_o_hex_list[2]) > 0:
            cell_format.set_bg_color(f_o_hex_list[2])
            worksheet.write(row, 3, '', cell_format)
        else:
            worksheet.write(row, 3, 'X')

        worksheet.write(row, 4, f'{round(f_o_t1_rgb[0] * 100) / 100:.2f}')
        # omitting many similar lines for brevity
        worksheet.write(row, 13, f'{vj:.2f}')

    # Close the file
    workbook.close()

Environment

- XlsxWriter version: 3.0.3
- Python version: 3.9
- Excel version: N/A (I open the xlsx files with Preview; my client uses Excel or Numbers.)
- OS: OS X 10.11.6 (El Capitan)

Any other information

No response

OpenOffice and LibreOffice users

jmcnamara commented 2 years ago

the compiled app does not produce any xlsx file.

That seems unlikely. If there was any issue that caused xlsxwriter to not be able to create a file then it would raise a warning or exception.

It is more probable that the file is being created but not in the directory that you think it is in. Applications like py2app often use their own sandbox directory.

You should double check where the file is created by putting a simple print() in the code after you create the filename:

    cwd = os.getcwd()
    filename = cwd + "/" + str_year + str_month + str_day + str_hour + str_min + str_sec + ".xlsx"
    print(filename)

Also, this StackOverflow question indicates that cwd() in py2app doesn't give you the assumed current working directory and shows how to work around that: https://stackoverflow.com/questions/11642540/python-change-cwd-of-script-bundled-with-py2app

RandallWert commented 2 years ago

Thanks for your quick reply. I have checked my entire hard disk, and the xlsx file is not being created anywhere. I also tried the solution suggested in response to that StackOverflow question, and my results remained the same: running in the IDE works fine, running the compiled app produces no xlsx file.

I suspect that the problem resides in py2app rather than XlsxWriter, so I have posted an issue there, too. In the meantime, I am going to try to write a simple text file and see whether that works. My client is adept with Excel and Numbers and can import a csv if necessary and format it as they desire.

jmcnamara commented 2 years ago

Did you try putting in the print statement to see the file location?

RandallWert commented 2 years ago

Yes, and I must thank you for pushing me again to do that. It showed that it was trying to write the xlsx to .app/Contents/MacOS (similar to what that StackOverflow answer mentioned). But the xlsx was not there, either -- just two Unix executables, one named python and one named like my app. Also, the solution suggested in the answer to that StackOverflow question did not correct the target filepath to the desired directory.

I FaceTime with my son, the software engineer, every Sunday evening at this time anyway, so he guided me through the process of setting a relative path to the user's Desktop and putting the xlsx there. And now it works!

Thank you again for your quick replies. I have learned that the cwd is not always what I think it is.

jmcnamara commented 2 years ago

Thanks for the followup and I'm glad you found a solution. Closing.