Running an Excel function through Python pywin32 - python

I am trying to run an Excel function through Python using pywin32. The function is a Reuters Excel add-on function (for, those unfamiliar, Reuters is a financial data provider).
from win32com import client
from paths import path_onedrive
import datetime as dt
today = str(dt.datetime.today().date()).replace('-','')
xlApp2 = client.Dispatch('Excel.Application')
xlApp2.Visible = True
wb = xlApp2.Workbooks.Add()
wb.SaveAs(fr'{path_onedrive}\reuters\{today}.xlsx')
ws_sheet1 = wb.Worksheets('Sheet1')
ws_sheet1.Cells(1, 'A').Value = '=TR("USDSROIS=";"BID;ASK;TRDPRC_1;HST_CLOSE";"CH=Fd RH=IN";B2)'
Where, =TR("USDSROIS=";"BID;ASK;TRDPRC_1;HST_CLOSE";"CH=Fd RH=IN";B2) is the Excel function that needs to be ran. The error I get is:
Traceback (most recent call last):
File "C:\Users\Sergej Shteriev\IdeaProjects\volatilityModels\classes_ir.py", line 23, in <module>
ws_sheet1.Cells(1, 'A').Value = '=TR("USDSROIS=";"BID;ASK;TRDPRC_1;HST_CLOSE";"CH=Fd RH=IN";B2)'
File "C:\ProgramData\Anaconda3\envs\volatilityModels\lib\site-packages\win32com\client\__init__.py", line 595, in __setattr__
self._oleobj_.Invoke(*(args + (value,) + defArgs))
pywintypes.com_error: (-2147352567, 'Exception occurred.', (0, None, None, None, 0, -2146827284), None)
Since Reuters Excel add-in requires a sign-in, I thought this might be the problem, so following from this post, I tried:
os.startfile(fr'{path_onedrive}\reuters\ReutersExcel.xlsx')
xlApp = client.GetObject(None, 'Excel.Application')
xlApp.Visible = True
where, ReutersExcel.xlsx is just an empty Excel file with the add-in signed in already. However, from here, I am not sure how to continue since client.GetObject and client.Dispatch don't return the same object with the same functions.

Related

SAP Analysis from Excel

I need to make a script that will automatically open Excel with COM setting - SAP Analysis from Excel.
I am learning the language and so I could not find the solution myself on Github/Stackoverflow.
It started with a simple line of code, but eventually I found the solution below.
But when I load Excel, the Analysis add-in doesn't open in the file. However, if you open the Excel file without the script, the add-in appears.
import win32com.client as win32
from pathlib import Path
sap_aof_excel_file = Path.cwd().joinpath(r"C:\Users\alexandrovn\Desktop\mo\MO2022.xlsm")
bwclient = "CODE"
bwuser = "LOGIN"
bwpassword = "PASS"
excel_instance = win32.gencache.EnsureDispatch('Excel.Application')
excel_instance.Visible = True
excel_instance.DisplayAlerts = False
workbook_sap = excel_instance.Workbooks.Open(sap_aof_excel_file, False, False)
for addin in excel_instance.Application.COMAddIns:
if addin.progID == 'SapExcelAddIn':
if addin.Connect == False:
addin.Connect = True
elif addin.Connect == True:
addin.Connect = False
addin.Connect = True
lResult = excel_instance.Application.Run("SAPLogon", "DS_1", bwclient, bwuser, bwpassword)
lResult = excel_instance.Application.Run("SAPExecuteCommand", "RefreshData", "DS_1")
workbook_sap.Save
workbook_sap.Close()
excel_instance.DisplayAlerts = True
excel_instance.Application.Quit()
excel_instance = None
workbook_sap = None
But when you load Excel, the Analysis add-in does not open in the file. However, if you open the Excel file without the script, the add-in appears. This is the error that appears:
C:\Users\alexandrovn\Anaconda3\python.exe C:/Users/alexandrovn/Desktop/mo/test.py
Traceback (most recent call last):
File "C:\Users\alexandrovn\Desktop\mo\test.py", line 30, in <module>
addin.Connect = True
File "C:\Users\alexandrovn\Anaconda3\lib\site-packages\win32com\client\dynamic.py", line 549, in __setattr__
self._oleobj_.Invoke(entry.dispid, 0, invoke_type, 0, value)
pywintypes.com_error: (-2147352567, 'Error.', (0, 'Microsoft.VisualStudio.Tools.Applications.Hosting', 'Failed to install the add-on.', None, 0, -2146233088), None)
Process finished with exit code 1
Explain what the error is and how to start Excel with this add-in? Maybe there is an access problem (working via corporate network and no administrator rights on the PC)
I don't think the code would persist the COM add-in. Better to take admin help and enable add-ins in AO

If sheet does not exist go to next Python

I'm writing a code that allows you to select the tables in a workbook sheet and send it by email. But it can happen that a sheet does not exist because there is no data.
I would like to know how I have the absence of a sheet and move to the other sends and also create a bouble for each sheet of the workbook instead of executing the same code on all the sheets.
I hope I have been precise.
I tried to continue without the error but the code (#import warnings #warnings.filterwarnings("ignore", category=DeprecationWarning)) does not work
like on "error resume next" in vba
Do you have another solution.
import win32com.client as win32
import xlwings as xw
import pandas as pd
import openpyxl
#import warnings
#warnings.filterwarnings("ignore", category=DeprecationWarning)
#wb = xw.Book()
wb = r"D:/Users/Desktop/Infos/MasterFile.xlsx"
data = xw.Book(wb)
Mylist_205 = data.sheets('Sheet_205')
selection_205=data.sheets('Sheet_205').used_range
Mylist_205.used_range.copy()
outlook = win32com.client.Dispatch("Outlook.Application")
# Create a new MailItem object
msg = outlook.CreateItem(0)
msg.To='servicesadvisor#infos.com'
msg.Subject = 'Subject'
msg.GetInspector.WordEditor.Range(Start=0, End=0).Paste()
msg.Display()
msg.Send()
Error:
Traceback (most recent call last):
File "C:/Users/sheets.py", line 17, in <module>
Mylist_205 = data.sheets('Sheet_205')
File "C:\Python\Python310\lib\site-packages\xlwings\main.py", line 4893, in __call__
return Sheet(impl=self.impl(name_or_index))
File "C:\Python\Python310\lib\site-packages\xlwings\_xlwindows.py", line 877, in __call__
return Sheet(xl=self.xl(name_or_index))
File "C:\Python\Python310\lib\site-packages\xlwings\_xlwindows.py", line 208, in __call__
v = self._inner(*args, **kwargs)
File "C:\Users\AppData\Local\Temp\gen_py\3.10\00020813-0000-0000-C000-000000000046x0x1x9.py", line 36625, in __call__
ret = self._oleobj_.InvokeTypes(0, LCID, 2, (9, 0), ((12, 1),),Index
pywintypes.com_error: (-2147352567,', (0, None, None, None, 0, -2147352565), None)
The first problem is that you are using () for .sheets. It is supposed to be []. I refactored it a bit because it is kind of confusing. I didn't test the email part of it, so I will only post what I tested.
I'm not sure what you are trying to put into your email, but after my code you can convert it to a dataframe or whatever.
One more thing about xlwings. Many times if you are working in a terminal, close the Excel application and then open the app again and try to run code against it, you might get the same pywintypes error. Try using the importlib module before you go nuts trying to debug it.
import importlib
import xlwings as xw
importlib.reload(xw)
Dummy file named MasterFile.xlsx:
import xlwings as xw
file_str= r"D:/Users/Desktop/Infos/MasterFile.xlsx"
wb = xw.Book(fpath)
dummy_sheets = [
'Sheet_201', 'Sheet_202', 'Sheet_204', 'Sheet_205', 'Sheet_206'
]
data = []
for sht in dummy_sheets:
try:
sht = wb.sheets[sht]
data.append(sht.used_range.value)
except:
# Do something else here.
print('Missing sheet.')

Running an Excel macro via Python?

I'm trying to run a macro via python but I'm not sure how to get it working...
I've got the following code so far, but it's not working.
import win32com.client
xl=win32com.client.Dispatch("Excel.Application")
xl.Workbooks.Open(Filename="C:\test.xlsm",ReadOnly=1)
xl.Application.Run("macrohere")
xl.Workbooks(1).Close(SaveChanges=0)
xl.Application.Quit()
xl=0
I get the following traceback:
Traceback (most recent call last):
File "C:\test.py", line 4, in <module>
xl.Application.Run("macrohere")
File "<COMObject <unknown>>", line 14, in Run
File "C:\Python27\lib\site-packages\win32com\client\dynamic.py", line 282, in _ApplyTypes_
result = self._oleobj_.InvokeTypes(*(dispid, LCID, wFlags, retType, argTypes) + args)
com_error: (-2147352567, 'Exception occurred.', (0, u'Microsoft Excel', u"Cannot run the macro 'macrohere'. The macro may not be available in this workbook or all macros may be disabled.", u'xlmain11.chm', 0, -2146827284), None)
EDIT
import win32com.client
xl=win32com.client.Dispatch("Excel.Application")
xl.Workbooks.Open(Filename="C:\test.xlsm",ReadOnly=1)
try:
xl.Application.Run("test.xlsm!testmacro.testmacro")
# It does run like this... but we get the following error:
# Traceback (most recent call last):
# File "C:\test.py", line 7, in <module>
# xl.Workbooks(1).Close(SaveChanges=0)
# File "C:\Python27\lib\site-packages\win32com\client\dynamic.py", line 192, in __call__
# return self._get_good_object_(self._oleobj_.Invoke(*allArgs),self._olerepr_.defaultDispatchName,None)
# com_error: (-2147352567, 'Exception occurred.', (0, None, None, None, 0, -2147352565), None)
except:
# Except isn't catching the above error... :(
xl.Workbooks(1).Close(SaveChanges=0)
xl.Application.Quit()
xl=0
I would expect the error is to do with the macro you're calling, try the following bit of code:
Code
import os, os.path
import win32com.client
if os.path.exists("excelsheet.xlsm"):
xl=win32com.client.Dispatch("Excel.Application")
xl.Workbooks.Open(os.path.abspath("excelsheet.xlsm"), ReadOnly=1)
xl.Application.Run("excelsheet.xlsm!modulename.macroname")
## xl.Application.Save() # if you want to save then uncomment this line and change delete the ", ReadOnly=1" part from the open function.
xl.Application.Quit() # Comment this out if your excel script closes
del xl
I did some modification to the SMNALLY's code so it can run in Python 3.5.2. This is my result:
#Import the following library to make use of the DispatchEx to run the macro
import win32com.client as wincl
def runMacro():
if os.path.exists("C:\\Users\\Dev\\Desktop\\Development\\completed_apps\\My_Macr_Generates_Data.xlsm"):
# DispatchEx is required in the newest versions of Python.
excel_macro = wincl.DispatchEx("Excel.application")
excel_path = os.path.expanduser("C:\\Users\\Dev\\Desktop\\Development\\completed_apps\\My_Macr_Generates_Data.xlsm")
workbook = excel_macro.Workbooks.Open(Filename = excel_path, ReadOnly =1)
excel_macro.Application.Run\
("ThisWorkbook.Template2G")
#Save the results in case you have generated data
workbook.Save()
excel_macro.Application.Quit()
del excel_macro
Just a quick note with a xlsm with spaces.
file = 'file with spaces.xlsm'
excel_macro.Application.Run('\'' + file + '\'' + "!Module1.Macro1")
I suspect you haven't authorize your Excel installation to run macro from an automated Excel. It is a security protection by default at installation. To change this:
File > Options > Trust Center
Click on Trust Center Settings... button
Macro Settings > Check Enable all macros
Hmm i was having some trouble with that part (yes still xD):
xl.Application.Run("excelsheet.xlsm!macroname.macroname")
cos im not using excel often (same with vb or macros, but i need it to use femap with python) so i finaly resolved it checking macro list:
Developer -> Macros:
there i saw that: this macroname.macroname should be sheet_name.macroname like in "Macros" list.
(i spend something like 30min-1h trying to solve it, so it may be helpful for noobs like me in excel) xD
A variation on SMNALLY's code that doesn't quit Excel if you already have it open:
import os, os.path
import win32com.client
if os.path.exists("excelsheet.xlsm"):
xl=win32com.client.Dispatch("Excel.Application")
wb = xl.Workbooks.Open(os.path.abspath("excelsheet.xlsm"), ReadOnly=1) #create a workbook object
xl.Application.Run("excelsheet.xlsm!modulename.macroname")
wb.Close(False) #close the work sheet object rather than quitting excel
del wb
del xl
I tried the win32com way and xlwings way but I didn't get any luck. I use PyCharm and didn't see the .WorkBook option in the autocompletion for win32com.
I got the -2147352567 error when I tried to pass a workbook as variable.
Then, I found a work around using vba shell to run my Python script.
Write something on the XLS file you are working with when everything is done. So that Excel knows that it's time to run the VBA macro.
But the vba Application.wait function will take up 100% cpu which is wierd. Some people said that using the windows Sleep function would fix it.
Import xlsxwriter
Shell "C:\xxxxx\python.exe
C:/Users/xxxxx/pythonscript.py"
exitLoop = 0
wait for Python to finish its work.
Do
waitTime = TimeSerial(Hour(Now), Minute(Now), Second(Now) + 30)
Application.Wait waitTime
Set wb2 = Workbooks.Open("D:\xxxxx.xlsx", ReadOnly:=True)
exitLoop = wb2.Worksheets("blablabla").Cells(50, 1)
wb2.Close exitLoop
Loop While exitLoop <> 1
Call VbaScript
For Python 3.7 or later,(2018-10-10), I have to combine both #Alejandro BR and SMNALLY's answer, coz #Alejandro forget to define wincl.
import os, os.path
import win32com.client
if os.path.exists('C:/Users/jz/Desktop/test.xlsm'):
excel_macro = win32com.client.DispatchEx("Excel.Application") # DispatchEx is required in the newest versions of Python.
excel_path = os.path.expanduser('C:/Users/jz/Desktop/test.xlsm')
workbook = excel_macro.Workbooks.Open(Filename = excel_path, ReadOnly =1)
excel_macro.Application.Run("test.xlsm!Module1.Macro1") # update Module1 with your module, Macro1 with your macro
workbook.Save()
excel_macro.Application.Quit()
del excel_macro

Cannot iterate VBA macros from Python

I am using VBA in conjunction with Python.
I imported the module OS, and for working with excel - openpyxl. The problem occurs when it iterates the function for running the VBA macro from Excel.
import random
from openpyxl import load_workbook
import os, os.path, win32com.client
wbi = load_workbook('Input.xlsm')
wsi = wbi.get_active_sheet()
wbo = load_workbook('Output.xlsx')
wso = wbo.get_active_sheet()
def run_macro(fName, macName, path=os.getcwd()):
"""
pre: fName is the name of a valid Excel file with macro macName
post: fName!macName is run, fName saved and closed
"""
fName = os.path.join(path, fName)
xlApp = win32com.client.Dispatch("Excel.Application")
fTest = xlApp.Workbooks.Open(fName)
macName = fTest.Name + '!' + macName
xlApp.Run(macName)
fTest.Close(1)
xlApp.Quit()
xlApp = None
def IBP():
ibp = wsi.cell('G12')
ibpv = random.randint(0,45)
ibp.value = ibpv
return ibp.value
def BP10():
bp10 = wsi.cell('G13')
bpv10 = random.randint(30,50)
bp10.value = bpv10
return bp10.value
for n in range(6):
IBP()
print IBP()
BP10()
run_macro('Input.xlsm','macro1')
wbo.save('Output.xlsx')
I think that the error is in run_macro('Input.xlsm','macro1') - it cannot iterate.
The output:
Qt: Untested Windows version 6.2 detected!
35
4
Traceback (most recent call last):
File "C:\Users\User\Desktop\Python Exp\Pr 1.py", line 77, in <module>
run_macro('Input.xlsm','macro1')
File "C:\Users\User\Desktop\Python Exp\Pr 1.py", line 18, in run_macro
fTest = xlApp.Workbooks.Open(fName)
File "C:\Python27\lib\site-packages\win32com\client\dynamic.py", line 522, in __getattr__
raise AttributeError("%s.%s" % (self._username_, attr))
AttributeError: Excel.Application.Workbooks
What am I doing wrong?
I'm not sure this will help, but you can try early binding. Run this script and then try yours again:
import win32com.client
xl = win32com.client.gencache.EnsureDispatch ("Excel.Application")
print xl.__module__
If that does not work, you can alway go back to late binding by hooking to Excel like this:
xl = win32com.client.dynamic.Dispatch("Excel.Application")
or by simply deleting this folder: C:\Python27\Lib\site-packages\win32com\gen_py\00020813-0000-0000-C000-000000000046x0x1x7
From the error message, it looks like your problem is on the line wb = xlApp.Workbooks.Open(fname). If the Python hooks to the Excel com servers were working correctly, then that line would not raise the exception that it did. I don't see anything wrong with the code where the exception occured. Sometimes early binding helps in situations like this.
good luck
Mike

Python win32com: Internet Explorer COM object ? (used to work?)

I have this very simple program:
from win32com import client
ie=client.Dispatch("InternetExplorer.Application")
This used to work (I think I broke something when I re-used 'makepy.py' to try and add in constants for IE).
It still works on another machine where I haven't been so slap-dash with 'makepy.py'.
Here's what I get in an interactive Python session on the non-working machine:
>>> ie
>>> <win32com.gen_py.Microsoft Internet Controls.IWebBrowser2 instance at 0x14701432
>
>>> ie.Visible=True
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "D:\Python26\lib\site-packages\win32com\client\__init__.py", line 471, in
__setattr__
self._oleobj_.Invoke(*(args + (value,) + defArgs))
pywintypes.com_error: (-2147352573, 'Member not found.', None, None)
And the same on a working machine:
>>> from win32com import client
>>> ie=client.Dispatch("InternetExplorer.Application")
>>> ie
>>> <ComObject InternetExplorer.Application>
>>> ie.Visible=1 # This then brings up IE correctly.
How do I get this working again ? Or am I using the wrong way of launching IE ?
Thanks !
Went into here:
Python26\Lib\site-packages\win32com\gen_py
Renamed the .py and .pyc file to .py_ and .pyc_ files :
85CC894D-5673-4868-9A22-9E15B7E694D3x0x1x1.pyc
Restarted Python: now get the Internet Explorer. phew...

Categories

Resources