Source code for exceldriver.tools
import os
import subprocess
import time
import pythoncom
import win32com.client
from win32com.client import Dispatch, GetActiveObject
from exceldriver.path import get_excel_path
from exceldriver.wb_template import XLSX_TEMPLATE_BINARY
from .exceptions import NoExcelWorkbookException
def _kill_excel():
os.system('taskkill /f /im excel.exe')
def _load_excel(visible=True):
xl = Dispatch('Excel.Application')
xl.Visible = visible
return xl
def _connect_to_running_excel(visible=True):
xl = GetActiveObject('Excel.Application')
xl.Visible = visible
return xl
def _restart_excel_with_addins_and_attach(restart_sleep=15, start_sleep=30, max_retries=3):
_kill_excel()
time.sleep(restart_sleep)
return _start_excel_with_addins_and_attach(sleep=start_sleep, tries_remaining=max_retries)
def _start_excel_with_addins_and_attach(sleep=30, tries_remaining=3):
if tries_remaining <= 0:
raise NoExcelWorkbookException('Tried 3 times and was still not able to start Excel and connect to open workbook')
try:
excel = _start_excel_and_attach(sleep=sleep)
except NoExcelWorkbookException:
time.sleep(10)
_kill_excel()
time.sleep(30)
excel = _start_excel_with_addins_and_attach(sleep=sleep, tries_remaining=tries_remaining - 1)
return excel
def _start_excel_and_attach(sleep=30):
_start_excel_with_addins(sleep=sleep)
return _get_excel_running_workbook('Book1.xlsx')
def _start_excel_with_addins(sleep=30):
command = new_excel_command()
subprocess.Popen(command)
time.sleep(sleep)
def _get_excel_running_workbook(workbook_name):
lenstr = len(workbook_name)
obj = None
rot = pythoncom.GetRunningObjectTable()
rotenum = rot.EnumRunning()
while True:
monikers = rotenum.Next()
if not monikers: break
ctx = pythoncom.CreateBindCtx(0)
name = monikers[0].GetDisplayName(ctx, None)
if name[-lenstr:] == workbook_name:
obj = rot.GetObject(monikers[0])
if obj is None:
raise NoExcelWorkbookException(f'Could not find open workbook {workbook_name}')
workbook = win32com.client.gencache.EnsureDispatch(obj.QueryInterface(pythoncom.IID_IDispatch))
return workbook.Application
[docs]def new_excel_command():
### TEMP
# Need to not hardcode filepaths. Can generalize by writing functions to find excel and create blank workbook
excel_filepath = get_excel_path()
# Need excel opening an empty workbook
wb_home_path = os.path.sep.join(['~','Book1.xlsx'])
workbook_filepath = os.path.expanduser(wb_home_path)
if not os.path.exists(workbook_filepath):
create_empty_workbook(workbook_filepath)
return _new_excel_command(excel_filepath, workbook_filepath)
[docs]def create_empty_workbook(outpath: str):
with open(outpath, 'wb') as f:
f.write(XLSX_TEMPLATE_BINARY)
def _new_excel_command(excel_filepath, workbook_filepath):
return f'"{excel_filepath}" "{workbook_filepath}"'