2

I have written a small program trivially converting quite a bit of data into an Excel sheet on Windows using xlsxwriter which I then manually open in Excel for further analysis.

If I already have the file open in Excel and forget to explicitly close it, xlsxwriter fails when it tries to save the in-memory sheet to disk with a Permission denied. I understand that this is how Windows behaves, as opposed to Linux.

I would like to detect that the file is already open in Excel in the beginning of my program so I can fail fast, instead after a while.

How do I detect this in Python 3.8.5?

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
Thorbjørn Ravn Andersen
  • 73,784
  • 33
  • 194
  • 347

1 Answers1

1

Here is one approach to checking if the file can be created in a try/except block.

For completeness it also shows how to check if the file is writeable at creation/close time (which might suit your purposes better):

import xlsxwriter

filename = 'test.xlsx'

# Try to opene() the file in a loop so that if there is an exception, such as
# if the file is open in Excel, we can ask the user to close the file.
while True:
    try:
        filehandle = open(filename, 'w')
        filehandle.close()
    except Exception as e:
        decision = input("Could open file: %s\n"
                         "Please close the file if it is open in Excel.\n"
                         "Try to write file again? [Y/n]: " % e)
        if decision != 'n':
            continue
        else:
            exit

    break

workbook = xlsxwriter.Workbook(filename)
worksheet = workbook.add_worksheet()

worksheet.write('A1', 'Hello world')

# Try to close() the file in a loop so that we can catch the exception.
# Note the XlsxWriter specific exception.
while True:
    try:
        workbook.close()
    except xlsxwriter.exceptions.FileCreateError as e:
        decision = input("Exception caught in workbook.close(): %s\n"
                         "Please close the file if it is open in Excel.\n"
                         "Try to write file again? [Y/n]: " % e)
        if decision != 'n':
            continue

    break

Note, this approach introduces a potential TOCTOU error but that may not be an issue for a simple use case.

jmcnamara
  • 38,196
  • 6
  • 90
  • 108
  • This is nice, but quite an overkill solution to my problem. The "just fail with an exception" is fine - I just want it to happen up front, and not when the writing finally happens. – Thorbjørn Ravn Andersen Oct 13 '20 at 10:35