How to catch a pywin32com exception on opening files - python

I am trying to open an excel file in python using COM, and trying to catch the file not found error:
I first tried catching the IOError:
try:
output = xl.Workbooks.Open(Params.workbookName)
except IOError as reason:
print reason
exit()
But COM doesn't raise an IO Error when it has a file not found problem, instead it raises something called com_error:
com_error: (-2147352567, 'Exception
occurred.', (0, u'Microsoft Office
Excel', u"'asdf.xlsx' could not be
found. Check the spelling of the file
name, and verify that the file
location is correct.\n\nIf you are
trying to open the file from your list
of most recently used files, make sure
that the file has not been renamed,
moved, or deleted.", u'C:\Program
Files (x86)\Microsoft
Office\Office12\1033\XLMAIN11.CHM',
0, -2146827284), None)
so logically I tried this:
try:
output = xl.Workbooks.Open(Params.workbookName)
except com_error as reason:
print reason
exit()
but...
NameError: global name 'ComError' is not defined

Try:
from pythoncom import com_error
and catch it in your except block

Related

Running an Excel macro via Python? (New problem - saving)

I already saw this question in other link but I'm new here and i don't have reputation to comment there.
I made the script works and the macro run but when saving the file instead of just saving, it opens a excel pop-up asking if i confirm the changes. How do I save directly without opening this pop-up?
my code (edited):
import os.path
import win32com.client as wincl
if os.path.exists("C:\\Users\\peo_cpena\\Downloads\\excel.xlsx"):
try:
xl = wincl.Dispatch("Excel.Application")
xl.Workbooks.Open(os.path.abspath(
"C:\\Users\\peo_cpena\\Downloads\\excel.xlsx"))
xl.Application.Run("macro2.xlsm!Macro2")
xl.Application.Workbooks("excel.xlsx").Save()
xl.Application.DisplayAlerts = False
xl.Application.Workbooks("excel.xlsx").Quit(False)
del xl
except:
xl.Application.Quit()
print("It didn't work")
del xl
Removing the Try i received this error:
Traceback (most recent call last):
File "C:/Users/peo_cpena/PycharmProjects/Cursoemvideo/UOL/CalculoImpARG.py", line 14, in <module>
xl.Application.Workbooks("C:\\Users\\peo_cpena\\Downloads\\Vendas_por_Repasse_Aeria_Games_Europe_GmbH_01102020-31102020.xlsx").Save()
File "C:\Users\peo_cpena\PycharmProjects\Cursoemvideo\venv\lib\site-packages\win32com\client\dynamic.py", line 197, in __call__
return self._get_good_object_(self._oleobj_.Invoke(*allArgs),self._olerepr_.defaultDispatchName,None)
pywintypes.com_error: (-2147352567, 'Exceção.', (0, None, None, None, 0, -2147352565), None)
Try explicitly saving the workbook before closing it:
xl.Application.Workbooks("excel.xlsx").Save()
xl.Application.Workbooks("excel.xlsx").Close(False)

Running VBA code from Python: macros may be disabled

Trying to run an Excel macro via Python I get the following error:
Traceback (most recent call last):
File ".\test.py", line 17, in <module>
xlApp.Application.Run(MACRO)
File "<COMObject <unknown>>", line 14, in Run
File "C:\Users\twauchop\Desktop\Python\virtual_envs\gutenberg\lib\site-packages\win32com\client\dynamic.py", line 287, in _ApplyTypes_
result = self._oleobj_.InvokeTypes(*(dispid, LCID, wFlags, retType, argTypes) + args)
pywintypes.com_error: (-2147352567, 'Exception occurred.', (0, 'Microsoft Excel', "Cannot run the macro 'test'. The macro may not be available in this workbook or all macros may be disabled.", 'xlmain11.chm', 0, -2146827284), None)
I tried many of the fixes suggested in other questions.
I tried 'xlApp.Application.Run(wb.name + "!" + MACRO)'.
Is this a naming convention issue? I enabled everything via Trust Center and changed the VBA sub to public.
As a side-note, I also cannot run macros from the programmatically opened workbook (i.e. if I try manually). If I open the workbook manually, however, everything is fine.
I am running Python 3.6.5 on a 64 bit system, Windows 10.
Python:
import win32com.client
import os
import traceback
DIRECTORY = r'C:\\Users\\twauchop\\Desktop\\Excel\\'
FILE = 'test.xlsb'
MACRO = 'test'
path = os.path.join(DIRECTORY, FILE)
if os.path.exists(path):
try:
xlApp = win32com.client.Dispatch('Excel.Application')
xlApp.DisplayAlerts = False
xlApp.Visible = True
wb = xlApp.Workbooks.Open(Filename=path, ReadOnly=1)
xlApp.Application.Run(MACRO)
wb.Close(SaveChanges=1)
xlApp.Application.Quit()
print('Code ran successfully.')
except:
print('An error was encountered; see traceback.')
print(traceback.format_exc())
xlApp.Quit()
VBA:
Public Sub test()
MsgBox "Hello World!"
End Sub
xlApp.Application.AutomationSecurity=1 needs to go before ANY xlApp.Application.Run(excelMacroNameHere) code, as the AutomationSecurity is used to control (enable vs disable) macros and 1 means enable all macros.

How to Get pywin32 Methods to Accept Variable Parameters

I'm using pywin32 to write a program that sends email notifications. Based on error exceptions
def main(recipient):
try:
mailer = Dispatch("Outlook.Application")
msg = mailer.CreateItem(0)
msg.To = recipient
msg.CC = ""
msg.Subject = "EmailTest"
msg.Body = "This is most certainly a test"
msg.Send()
success(msg.Subject, recipient)
except Exception:
failure(msg.Subject, recipient)
When the parameters to the success and fail methods are variables (with string values) it returns the error:
Traceback (most recent call last):
File "C:\pathtoprogram\thisprogram.py", line 48, in main
success(msg.Subject, recipient)
File "C:\Users\myuser\AppData\Local\Programs\Python\Python36-32\lib\site-packages\win32com\client\dynamic.py", line 516, in __getattr__
ret = self._oleobj_.Invoke(retEntry.dispid,0,invoke_type,1)
pywintypes.com_error: (-2147352567, 'Exception occurred.', (4096, 'Microsoft Outlook', 'The item has been moved or deleted.', None, 0, -2147221238), None)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "<interactive input>", line 1, in <module>
File "C:\pathtoprogram\thisprogram.py", line 50, in main
failure(msg.Subject, recipient)
File "C:\Users\myuser\AppData\Local\Programs\Python\Python36-32\lib\site-packages\win32com\client\dynamic.py", line 516, in __getattr__
ret = self._oleobj_.Invoke(retEntry.dispid,0,invoke_type,1)
pywintypes.com_error: (-2147352567, 'Exception occurred.', (4096, 'Microsoft Outlook', 'The item has been moved or deleted.', None, 0, -2147221238), None)
I don't know what's creating the exception, but the code works fine when I enter the parameters directly as strings.
success("mySubject", "anEmail")
except Exception:
failure("mySubject", "anEmail")
That code works will run fine, but I need the parameters to be variables because they need to be able to be passed in from the main method.
I've been looking up answers to similar problems but I haven't found one that pertains to this issue. It seems like msg.Subject and msg.To don't actually store string values even though they're in what looks like any other assignment statement. Maybe it's an obvious thing I'm missing?
Any help would be greatly appreciated.
I'm using python 3.6 and the corresponding version of pywin32.
The problem is not with the way you are using the variables. You can test this by checking the values of msg.Subject before you call msg.Send()
Refer to the CDO (collaboration data objects) documentation from Microsoft, specifically for the Send method:
https://msdn.microsoft.com/en-us/library/ms527190(v=exchg.10).aspx
Send moves the message to the current users Outbox folder. Messaging systems retrieve messages from the Outbox and transport them to the recipients. After it is transported, a message is removed from the Outbox and deleted unless saveCopy is True.*
Refer to the error message you were getting:
4096, 'Microsoft Outlook', 'The item has been moved or deleted.'
So the system is doing what it was designed to do - delete the message after you send it.

Opening Word from Python, unexpected behaviour

I'm writing a script to parse word document and get certain outputs. I use the following commands for reading the desired document.
import win32com.client as win32
import Tkinter,tkFileDialog
root = Tkinter.Tk()
root.withdraw()
filename = tkFileDialog.askopenfilename() # getting filename through windows explorer
word = win32.Dispatch("Word.Application")
#word.Documents.Open(filename)
The last line which is commented is how I was planning to implement this. But whenever I try to open a file which has a space in it's filename, this fails. In fact I found that if I give word.Documents.Open("C:/Python27/word sample.docm")
This will also fail, but if I use backslash after C: it'll work perfectly.
In short the below commands for opening document will work:
word.Documents.Open("C:\Python27/word sample.docm")
word.Documents.Open(filename) #if filename don't have a space
And the below ones will not work:
word.Documents.Open("C:/Python27/word sample.docm")
word.Documents.Open(filename) #filename have a space in it
Could someone explain what is going wrong here?
This is the error that I'm receiving:
C:\Users\xxx>C:\Python27\python.exe C:\Python27\test.py
Traceback (most recent call last):
File "C:\Python27\test.py", line 10, in <module>
word.Documents.Open("C:/Python27/word sample.docm")
File "<COMObject <unknown>>", line 8, in Open
pywintypes.com_error: (-2147352567, 'Exception occurred.', (0, u'Microsoft Word'
, u'This file could not be found.\r (C:\\//Python27/word%20sample.docm)', u'
wdmain11.chm', 24654, -2146823114), None)

Calling a subprocess in Python 3.4 and handling errors if a command is invalid?

I am trying to execute an external process in Python 3.4. When my "command" is wrong the program just crashes. How can I handle the errors gracefully and recover?
# Call a system process
try:
pipe = subprocess.Popen(command,
stdout=subprocess.PIPE)
except (OSError,
subprocess.CalledProcessError) as error:
print("Failed to execute command")
print(command)
print("Error: " + error.output)
while True:
output = pipe.stdout.readline()
if not output:
print("Finished...")
break
output = output.decode()
output = output.strip("\r")
output = output.strip("\n")
print(output)
When I call an invalid command. I get a crash like:
C:\SDKs\Python34\python.exe C:\Users\user\Documents\GitHub\PyQtApps\QtDeploy\src\main.py
Traceback (most recent call last):
Executing: windeployqt.exe C:\Users\user\Documents\GitHub\SpaCentralSoftBin\GUIController.exe
File "C:\Users\user\Documents\GitHub\PyQtApps\QtDeploy\src\forms\maindialog.py", line 81, in execute_windeployqt
Failed to execute command
stdout=subprocess.PIPE)
windeployqt.exe C:\Users\user\Documents\GitHub\SpaCentralSoftBin\GUIController.exe
File "C:\SDKs\Python34\lib\subprocess.py", line 858, in __init__
restore_signals, start_new_session)
File "C:\SDKs\Python34\lib\subprocess.py", line 1111, in _execute_child
startupinfo)
FileNotFoundError: [WinError 2] The system cannot find the file specified
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "C:\Users\user\Documents\GitHub\PyQtApps\QtDeploy\src\forms\maindialog.py", line 159, in on_buttonBox_clicked
self.execute_windeployqt()
File "C:\Users\user\Documents\GitHub\PyQtApps\QtDeploy\src\forms\maindialog.py", line 86, in execute_windeployqt
print("Error: " + error.output)
AttributeError: 'FileNotFoundError' object has no attribute 'output'
The larger problem is printing an error message does not "handle" an error in any meaningful sense of "handle" (although many people think it does).
Log an error message if you want and then exit your program. There are few instances where you can handle an error, for example if a configuration file can't be read, see if you can read a global configuration file or KeyboardInterrupt can be passed up to a main loop that is reading commands.
In your example, if you didn't fault in the except block, the output = pipe.stdout... would yield:
NameError: name 'pipe' is not defined
and if you caught that, there'd still be nothing meaningful to do to recover the state your code expects to be in. You'll also move the traceback you do get to a place where the fault isn't.
A good idiom for your situation is
except SomeError:
log what you want
raise
where an empty raise re-raises the last exception which will propagate up, forming a full stacktrace which will give you a better idea of where the fault is. If you don't do this, you are discarding useful information.
FileNotFoundError' object has no attribute 'output'
Use
print("Error: " + error)
FileNotFoundErrr has these properties which might be useful:
args
characters_written
errno
filename
filename2

Categories