Home > OS >  Use win32com to Open Excel file with formulas, add some delay, & save as CSV
Use win32com to Open Excel file with formulas, add some delay, & save as CSV

Time:11-25

I have an Excel file that has a bunch of formulas in them. It takes time for the formulas to properly load (~1-2 mins), so I'm trying to add some delay between opening the file and saving the loaded file. After this is done, I'm hoping to save a copy of the fully loaded Excel file as a new CSV with a different name, so that I have both the fully loaded Excel file and new CSV file.

To be clear, I'm trying to do the following tasks in this order:

  1. Open the Excel file
  2. Add some delay (~1-2 mins long)
  3. Save the fully loaded Excel file
  4. Save a copy of the fully loaded Excel file as a CSV with a different name

I've managed to do Steps 1 and 3 as seen below, but am having trouble with Steps 2 and 4. I've noticed Step 2 is quite important, since the way my code is written right now does not allow for enough time for the formulas to load, leading to an incompletely-loaded file.

What is the best way to do Steps 2 and 4, i.e., add delay and then save the full file as a CSV?

import win32com.client as win32

excel = win32.gencache.EnsureDispatch('Excel.Application')

#opens file denoted by PATH
workbook = excel.Workbooks.Open(PATH)

#saves file
workbook.Save()

#closes and quits Excel
workbook.Close()
excel.Quit()

Note this code is based on this post.

CodePudding user response:

You can kick off the Excel calculation, then have your Python code wait:

import time

#...
workbook = excel.Workbooks.Open(PATH)
excel.CalculateFull() #If Calculation is set to Manual
#Wait 10 seconds
time.sleep(10)
workbook.Save()
#...

Of course, you don't know if 10 seconds is too long or too short a time to wait.

A more precise way is to start the calculation and then wait for Excel to tell you it has finished. The Excel Application object signals a AfterCalculation event when it has completed the calculation tree. You can set up your Python code to wait for this event to be signalled before proceeding.

Full code:

import win32com.client as wc
import pythoncom #From package pywin32
import win32api
import win32con
from os.path import join

#Class to handle the SyncObject events from Outlook
class CalcHandler(object): 
    def OnAfterCalculate(self):
        #Calculation has finished so send WM_QUIT to message loop
        win32api.PostThreadMessage(win32api.GetCurrentThreadId(), win32con.WM_QUIT, 0, 0)       
        print('... calculation complete')

#Get the application Dispatch interface
xl = wc.gencache.EnsureDispatch('Excel.Application')

path = 'path_to_directory'

#opens a file
workbook = xl.Workbooks.Open(join(path,'test.xlsx'))

if workbook is not None:
    #Create an event handler
    wc.WithEvents(xl,CalcHandler)

    print('Starting calculation ...')
    #Force a calcuation
    xl.CalculateFull()

    #This will block until a WM_QUIT message is sent to the message queue
    pythoncom.PumpMessages()

    #saves file as a CSV
    xl.DisplayAlerts=False
    workbook.SaveAs(join(path,'test.csv'),wc.constants.xlCSV)

    #closes and quits Excel
    workbook.Close()

if xl.Workbooks.Count == 0:
    xl.Quit()
    xl=None
  • Related