0

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.

mouwsy
  • 1,457
  • 12
  • 20

2 Answers2

1

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()
mouwsy
  • 1,457
  • 12
  • 20
1

I found this code snippet here. Using this psutil library it gets all the processes you have running, checks if a string is in the process (ie. Adobe, EXCEL) and kills those processes. This worked well using Python 3 and Windows 10 to kill Excel sessions that continued to run in the background after I had opened and "closed" them with Win32com.

import psutil

def main():
    '''Process kill function'''    
    for proc in psutil.process_iter():
        # check whether the process name matches
        # print(proc.name())
        if any(procstr in proc.name() for procstr in\
            ['Adobe', 'EXCEL']):
            print(f'Killing {proc.name()}')
            proc.kill()


if __name__ == "__main__":
    main()
GoPackGo
  • 341
  • 5
  • 9
  • Could you extend your code so that the code only closes the process if an error message occurs? The process in the background that is opend with the python code should only close, if I receive an error message. Right now it just does the same job as the last code snippet in the question text. – mouwsy Apr 22 '21 at 19:51