I am using the following xlwings code on MacOS to read a large Excel spreadsheet containing many formulae to be executed:
import xlwings as xl
app = xl.App(visible=False)
book = app.books.open("large.xlsx")
book.save()
app.kill()
Attempting to execute this code leads to a CommandError: "Apple event timed out", full stack trace:
File "./open_excel_file.py", line 32, in open_excel_file
book = app.books.open("large.xlsx")
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/xlwings/main.py", line 2889, in open
impl = self.impl.open(fullname, update_links, read_only, format, password, write_res_password,
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/xlwings/_xlmac.py", line 209, in open
self.app.xl.open_workbook(workbook_file_name=fullname, update_links=update_links, read_only=read_only,
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/aeosa/appscript/reference.py", line 518, in __call__
raise CommandError(self, (args, kargs), e, self.AS_appdata) from e
appscript.reference.CommandError: Command failed:
OSERROR: -1712
MESSAGE: Apple event timed out.
COMMAND: app('/Applications/Microsoft Excel.app', newinstance=(0, 34521322)).open_workbook(workbook_file_name='large.xlsx', update_links=k.do_not_update_links, read_only=None, format=None, password=None, write_reserved_password=None, ignore_read_only_recommended=None, origin=None, delimiter=None, editable=None, notify=None, converter=None, add_to_mru=None)
Is there a way to use xlwings to open this file, execute all of the formulae and then save it again, without encountering this timeout?
xlwings currently goes with the default timeout from the underlying appscript. If this happens during the save event, you should be able to do this as a workaround until this is fixed: workbook.api.save(timeout=3000), see: https://github.com/xlwings/xlwings/issues/618
Edit:
To open a workbook works like this:
import xlwings as xw
app = xw.App(visible=False)
book = app.api.open_workbook(workbook_file_name='/full/path/to/large.xlsx', timeout=3000)
I'll try to add native support with the next release.
Related
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.')
Here is my problem. We have an Excel based report that business users enter comments into two separate fields, as well as selecting a code form a drop down. We then have a manual process that collects those files and pushes the comments and codes to a Snowflake table to be able to use in various reports.
I am trying to improve the process with a Python script that will collect the files, copy them to a staging_folder location, then read in the data from the sheet, append it all together, do some cleanup and push to Snowflake. The plan is that this would be completely automated - but this is where we run into issues.
Initial step works perfectly. I have a loop that grabs the files based on the previous business day date, copies them to a staging folder. There are typically 32 files each day.
Next step reads those files to append to a dataframe. Here is the function that is loading the Excel files in my Python script.
def load_files():
file_list = glob.glob(file_path + r'\*')
df = pd.DataFrame()
print("Importing data to Pandas DF...")
for file in file_list:
try:
wb = load_workbook(file)
ws = wb["Daily Outs"]
data = ws.values
cols = next(data)[1:]
data = list(data)
idx = [r[0] for r in data]
data = (islice(r, 1, None) for r in data)
data_1 = pd.DataFrame(data, index=idx, columns=cols)
df = df.append(data_1, sort=False)
print(file + " Imported to Df...")
except Exception as e:
print("Error: " + e + " When attempting to open file: " + file)
# error_notify(e)
print(df.head(10))
return df
The problem is when we have files that have some sort of corruption. The files when opened manually will show an error like the one below.
I thought with my try, except code above this would catch an error like this and alert me with the error_notify(e) function. However, we get a result where the Python script crashes with an error like this: zipfile.BadZipFile: File is not a zip file
During handling of the above exception, another exception occurred.
There is more to the error, but I only copied & pasted this part in some communication with some folks int he office. Impossible to replicate the error on our own - I have no idea how the files get corrupted in this way - except that there are multiple people accessing the files throughout the day.
The way to make the file readable is completely manual - we must open the file, get that error, hit yes, and save the file over the existing one. Then re-launch the script. But since the try, except isn't catching it and alerting us to the failure, we have to run the script manually to see if it works or not.
Two questions - am I doing something incorrect in my try, except command? I am admittedly weak in error catching so my first thought is there is more I can do there to make that work. Secondly, is there a Python way to get past that error in the Excel workbook files?
Here is the error text:
Traceback (most recent call last):
File "G:/Replenishment/Reporting/00 - I&A Replenishment/02 - Service
Level/Daily Outs Comment Capture/Python/daily_outs_missed_files.py", line 48, in load_files
wb = load_workbook(file)
File "C:\ProgramData\Anaconda3\lib\site-packages\openpyxl\reader\excel.py", line 314, in load_workbook
data_only, keep_links)
File "C:\ProgramData\Anaconda3\lib\site-packages\openpyxl\reader\excel.py", line 124, in init
self.archive = _validate_archive(fn)
File "C:\ProgramData\Anaconda3\lib\site-packages\openpyxl\reader\excel.py", line 96, in _validate_archive
archive = ZipFile(filename, 'r')
File "C:\ProgramData\Anaconda3\lib\zipfile.py", line 1222, in init
self._RealGetContents()
File "C:\ProgramData\Anaconda3\lib\zipfile.py", line 1289, in _RealGetContents
raise BadZipFile("File is not a zip file")
zipfile.BadZipFile: File is not a zip file
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "G:/Replenishment/Reporting/00 - I&A Replenishment/02 - Service Level/Daily Outs Comment Capture/Python/daily_outs_missed_files.py", line 123, in <module>
main()
File "G:/Replenishment/Reporting/00 - I&A Replenishment/02 - Service Level/Daily Outs Comment Capture/Python/daily_outs_missed_files.py", line 86, in main
df_output = df_clean()
File "G:/Replenishment/Reporting/00 - I&A Replenishment/02 - Service Level/Daily Outs Comment Capture/Python/daily_outs_missed_files.py", line 68, in df_clean
df = load_files()
File "G:/Replenishment/Reporting/00 - I&A Replenishment/02 - Service Level/Daily Outs Comment Capture/Python/daily_outs_missed_files.py", line 61, in load_files
print("Error: " + e + " When attempting to open file: " + file)
TypeError: can only concatenate str (not "BadZipFile") to str
Your try/except code looks correct. All user defined exceptions in python should be classes based on Exception. See BaseException and
and Exception in python documentation :
"Exception (..) All user-defined exceptions should also be derived from this class" see also the exception class hierarchy tree at the end of the python doc sesction.
If your python script "crashes" it means one of the library procedures throws an exception which is not based on the Exception class, something that "should not" be. You could look at the Traceback and try catching the offending exception type separately, or find what part of the source code and which library is the cause, fix it and submit a PR. Here are two examples of a good and bad way of deriving own exceptions
class MyBadError(BaseException):
"""
my bad exception, do not make yours that way
"""
pass
instead of recommended
class MyGoodError(Exception):
"""
exception based on the Exception
"""
pass
Where and what exactly fails is a bit of mystery still but the problems with your exception from the Traceback is not new, see zipfile.BadZipfile issue in pandas discussion. Note that xlrd used by pandas to read Excel workbooks data is currently a "no-maintainer-ware" declaration about xlrd from the authors and in case of any issues the recommendation is to use openpyxl instead or fix any issues yourself (pandas maintainers are doing pontius pilate on that, but happily use xlrd as a dependency). I suggest you catch the BadZipfile as a special known corruption error separately from all other exceptions, see python error handling tutorial for example code (you probably already have seen it, this is for other readers). If that does not work I can trace it in the source code of your libraries / python modules to the exact offending section and find the culprit, if you reach out directly.
I am trying out an utorrent automation using pywinauto lib. I want to add a torrent with URL. This option is under the file menu. I can get as far as opening uTorrent and then nothing happens. I used Swapy for generating this code. The box below opens only when I run the code in swapy. But when I save it into a file and run with cmd, only utorrent opens and a traceback occurs in the cmd.
from pywinauto.application import Application
app = Application().Start(cmd_line=u'"C:\\Users\\User\\AppData\\Roaming\\uTorrent\\u Torrent.exe" ')
torrentdfb = app[u'\xb5Torrent4823DF041B09']
torrentdfb.Wait('ready')
menu_item = torrentdfb.MenuItem(u'&File->Add Torrent from &URL...\tCtrl+U')
menu_item.Click()
app.Kill_()
Traceback:
Traceback (most recent call last):
File "AddTorrent.py", line 5, in <module>
torrentdfb.Wait('ready')
File "C:\Python27\lib\site-packages\pywinauto\application.py", line 380, in Wait
WaitUntil(timeout, retry_interval, lambda: self.__check_all_conditions(check_method_names))
File "C:\Python27\lib\site-packages\pywinauto\timings.py", line 308, in WaitUntil
raise err
pywinauto.timings.TimeoutError: timed out
I am new to python coding and I am not an expert. It would be helpful if you provide the explanation to solve my problem or the code. Thanks!!
uTorrent is spawning another process, this is how I got it:
>>> app.windows_()
[]
>>> app.process
6096
>>> app.connect(title_re=u'^μTorrent.*(build \d+).*')
<pywinauto.application.Application object at 0x000000000405C240>
>>> app.process
4044L
This is a final code working for me (with 32-bit uTorrent and 32-bit Python 2.7):
import pywinauto
app = pywinauto.Application().start(r'uTorrent.exe')
time.sleep(5) # because method connect() has no timeout param yet (planned for 0.6.0)
app.connect(title_re=u'^\u03bcTorrent.*(build \d+).*')
main_window = app.window_(title_re=u'^\u03bcTorrent.*(build \d+).*')
main_window.MenuSelect(u'&File->Add Torrent from &URL...\tCtrl+U')
app.AddTorrentFromURL.Edit.SetText('some URL')
app.AddTorrentFromURL.OK.Click()
Bitness is important. 32-bit uTorrent crashes if I use 64-bit 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
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