Search code examples
pythonexcelpywin32xlwings

Excel.exe process keeps on running if visible false after any error


Usually I use the following code to open an excel workbook in the background:

import xlwings as xw

app = xw.App(visible=False)
wb = xw.Book(filename)
sheet = wb.sheets['sheet1']

I sometimes do not code correctly and get an error message when I execute a code containing the above lines (with visible=False). In this case, the EXCEL.EXE process stays open on the processes list (in windows task manager on windows 10) in the background. Is there a solution that closes the particular excel process in the background that is opend with the python code, if I receive an error message? Otherwise for each time the code is executed with an error one extra excel process gets added to the process list resulting in less performance.

Currently, my workaround is to add the following lines at the top of the python script, but this closes all excel processes:

import subprocess
subprocess.call(["taskkill", "/f", "/im", "EXCEL.EXE"])

My objective is to close only that particular process that is opend with the python script.


Solution

  • Preferred solution
    xlwings added a solution in v0.24.3 to this problem:
    [Enhancement] xlwings.App() can now be used as context manager, making sure that there are no zombie processes left over on Windows, even if you use a hidden instance and your code fails. It is therefore recommended to use it whenever you can, like so:

    import xlwings as xw
    with xw.App(visible=False) as app:
        wb = xw.Book("test.xlsx")
        sheet = wb.sheets['sheet1']
        # To evoke an error, I try to call an non-exisiting sheet here.
        nonexistent_sheet["A1"]
    

    The with-line prevents that a EXCEL.EXE process stays open in windows task manager, even if you have an error in the code.

    Solution before v24.0.3
    Less elegant: Errors are caught by the except block, which means your main purpose of the script should be written in the try block.

    import xlwings as xw
    import traceback
    
    app = xw.App(visible=False)
    wb = xw.Book("test.xlsx")
    sheet = wb.sheets['sheet1']
    
    # Do what you want here. To evoke an error, I try to call an non-exisiting sheet here.
    try:
        not_existing_sheet["A1"]
    
    # Sources for except block: https://stackoverflow.com/a/31609619/13968392 and https://stackoverflow.com/a/54396161/13968392
    except BaseException:
        print(traceback.print_exc())
        app.quit()