python3 and pywin32 closing excel - python

I am having an issue closing excel after using Dispatch.
import openpyxl
import os
from win32com import client
class CTAutomation:
def __init__(self, file):
self.invoice = xl.load_workbook(os.getcwd() + "\Templates\ctrates.xlsx")
self.xlTemplate = xl.load_workbook(os.getcwd() + "\Templates\invoiceTemplate.xlsx")
self.vpc = xl.load_workbook(os.getcwd() + "\Templates\Vpc.xlsx")
self.file = file
def invoice_make(self):
self.xlApp = client.Dispatch("Excel.Application")
self.xlbook = self.xlApp.Workbooks.Open(os.getcwd() + '\TestFiles\\' + self.file)
self.ws = self.xlbook.Worksheets[0]
self.ws.Visible = 1
self.ws.ExportAsFixedFormat(0, os.getcwd() + "\complitedpdf\\" + self.file + ".pdf")
self.quit()
def quit(self):
self.xlbook.Close()
self.xlApp.Quit()
def xlformater(self):
return None
def main():
pwd = os.listdir(os.getcwd() + "\TestFiles")
for file in pwd:
CTAutomation(file.strip(".xlsx")).invoice_make()
if __name__ == "__main__":
main()
all works well till this part. i have found a few posts about this topic in the forum but i feel that im still missing something to close the app,
.xlsx and xls(Latest Versions) to pdf using python in example
some advice would be much appreciated .

Essentially it is your class object persisting in memory. Consider wrapping the process in a context manager using with(). And call the invoice_make() within the context.
Additionally, you had an incorrect Excel method by indexing workbook by zero with square brackets.
Finally, consider using os.path.join() to aviod back or forward slashes and use a try/except block to catch COM exceptions and properly release objects from memory.
import openpyxl as xl
import os
from win32com import client
cwd = os.getcwd()
class CTAutomation:
def __init__(self):
self.invoice = xl.load_workbook(os.path.join(cwd, "Templates", "ctrates.xlsx"))
self.xlTemplate = xl.load_workbook(os.path.join(cwd, "Templates", "invoiceTemplate.xlsx"))
self.vpc = xl.load_workbook(os.path.join(cwd, "Templates", "Vpc.xlsx"))
def invoice_make(self, file):
try:
self.xlApp = client.Dispatch("Excel.Application")
self.xlbook = self.xlApp.Workbooks.Open(os.path.join(cwd, "TestFiles", file))
self.ws = self.xlbook.Worksheets(1) # USE PARENTHESES (NOT BRACKETS AND NON-ZERO INDEX)
#self.ws.Visible = 1 # KEEP PROCESS IN BACKGROUND
self.ws.ExportAsFixedFormat(0, os.path.join(cwd, "complitedpdf", file.replace(".xlsx",".pdf")))
self.xlbook.Close(False)
self.xlApp.Quit()
except Exception as e:
print(e)
finally:
self.ws = None # RELEASE EXCEL OBJS FROM MEMORY
self.xlbook = None
self.xlApp = None
def xlformater(self):
return None
def __enter__(self):
return self # BOUND TO as IN with()
def __exit__(self, *err):
return None
def main():
pwd = os.listdir(os.path.join(cwd, "TestFiles"))
with CTAutomation() as obj: # CONTEXT MANAGER
for file in pwd:
print(file)
obj.invoice_make(file)
if __name__ == "__main__":
main()

Related

do not continue when exception

I would like use "try except" statement, but in two function. I caught an exception in function, but function2 does anyway. How can i stop it until there is an exception
i want to transfer it to a window application. If the file does not load, I want to display an information window. I only want the program to go on (function2) when the file loads
class Files:
def __init__(self):
self.name = "fle.txt"
def function(self):
try:
self.f = open(self.name, 'rb')
except OSError:
print("Problem!!!")
def function2(self):
print(self.f.read())
def main():
file=Files()
file.function()
file.function2()
Don't catch an exception unless you actually know how to handle it.
class Files:
def __init__(self):
self.name = "fle.txt"
self.f = None
def function(self):
self.f = open(self.name, 'rb')
def function2(self):
if self.f is None:
raise Exception("File not initialized!") #Example
#return #just if you don't throw or exit
print(self.f.read())
def main():
file=Files()
try:
file.function()
except OSError:
print("Problem!!!")
else:
file.function2()
main()
Wrap your function calls in a higher level try/except.
Of course, you would never write anything like this because it's so inflexible. This answer does not condone the OP's approach but suggests how that could be made to work.
class Files:
def __init__(self):
self.name = 'fle.txt'
def function_1(self):
self.fd = open(self.name)
def function_2(self):
print(self.fd.read())
def __del__(self):
try:
self.fd.close()
except Exception:
pass
file = Files()
try:
file.function_1()
file.function_2()
except Exception as e:
print(e)
So we don't do any exception handling (except in __del__ where we ignore any issues) within the class functions but allow all/any exceptions to propagate to the caller. Here we want to call two class functions but we wrap them in the same try/except block.
If function_1 raises an exception, function_2 won't be called.
del added to show how one could clean up but it's not the way this should be handled
#tomgalpin is right you could just exit right there after the problem
But this being a class maybe you want to print the error and pass back no data?
Here's one way to look at that with Tom's included sys exit (commented out)
Also be sure if you keep your code to close the file handler. Calling open on a file without .close() can leave file handlers open and cause problems for you if your class were to continue on after.
class Files:
def __init__(self):
self.name = "fle.txt"
# Empty string in data if no data
self.data = ""
def function(self):
try:
#self.f = open(self.name, 'rb')
with open(self.name, 'rb') as f:
self.data = f.read()
except OSError as err:
print("Problem!!!", err)
# You could exit
# sys.exit()
# But you could also return an empty string,
# which is "falsy", regardless of what happens
finally:
return self.data
def function2(self):
print(f"Data 3 {self.data}")
def main():
file=Files()
# You could print this, or use it to get the data
print("Data 1", file.function())
data = file.function()
print(f"Data 2 {data}")
# this now also shows the data
file.function2()
Use the variable that is usually True but becomes False if function fails
Example
class Files:
def __init__(self):
self.name = "file.txt"
self.Continue=True
self.data = ""
def function(self):
try:
#self.f = open(self.name, 'rb')
with open(self.name, 'rb') as f:
self.data = f.read()
except OSError as err:
print("Problem!!!", err)
self.Continue=False
return False
finally:
return self.data
def function2(self):
if self.Continue:
print(self.data)
else:
#Code if function failed
def main():
file=Files()
file.function()
file.function2()

Syntax error when running my classes on terminal

I am trying to create a file using luigi that will take a csv and create output the splits the data up into different dataframes based on whether or not a particular column in the csv contains a particular string
This is the file I created:
import luigi
import pandas as pd
import os
class read_file(luigi.Task):
fileName = luigi.Parameter()
def run(self):
full_file = pd.read_csv(self.fileName)
return full_file[['anonymous_id','channel','context_campaign_content',
'context_campaign_medium','context_campaign_name',
'context_campaign_source','context_campaign_term',
'timestamp','user_id','context_page_url',
'properties_url','properties_search','context_page_title',
'properties_path','context_user_agent','properties_referrer','rank']]
def output(self):
return full_file
class blog_readers(luigi.Task):
def run(self):
read_blog = read_file.full_file[read_file.full_file['properties_url'].str.contains('blog',regex=False)]
return read_blog
def requires(self):
return read_file
def output(self):
return read_blog
class logged_in(luigi.Task):
def run(self):
logged_in = read_file.full_file[read_file.full_file['properties_url'].str.contains('login',regex=False]
return logged_in
def requires(self):
return read_file
def output(self):
return logged_in
if __name__ == '__main__':
luigi.run()
However when I run this file on terminal-
python cleanup.py --local-scheduler read_blog --fileName '/Users/**/Desktop/file.csv'
I encounter this error message
File "cleancopy.py", line 64
logged_in = read_file.full_file[read_file.full_file['properties_url'].str.contains('login',regex=False]
^
SyntaxError: invalid syntax
I am not sure what the syntax error is being caused by

Limiting file size in Twisted FTP server

I am trying to implement an FTP server using twisted that limits the size of the uploaded file. Ideally this would happen before the transfer starts, but it is not really a problem if it exits gracefully during the transfer if it is too large.
I have started from the very basic ftpserver.py and slowly been pulling in more of the underlying classes from ftp.py to get down to the innards.
Current code below, please excuse the 'hack-and-slash' style employed until I can get it working.
#!/usr/bin/python
import os
from twisted.protocols.ftp import FTPFactory, FTPShell, FTPAnonymousShell, IFTPShell
from twisted.cred.portal import Portal
from twisted.cred.checkers import AllowAnonymousAccess
from twisted.internet import reactor, defer
from twisted.python import filepath, failure
class FileConsumer1(object):
def __init__(self, fObj):
self.fObj = fObj
def registerProducer(self, producer, streaming):
self.producer = producer
assert streaming
def unregisterProducer(self):
self.producer = None
self.fObj.close()
def write(self, bytes):
size = os.fstat(self.fObj.fileno()).st_size + len(bytes)
if size > 10:
raise Exception("File too large") # WHAT GOES HERE?
self.fObj.write(bytes)
class FileWriter1(object):
def __init__(self, fObj):
self.fObj = fObj
self._receive = False
def receive(self):
assert not self._receive, "Can only call IWriteFile.receive *once* per instance"
self._receive = True
return defer.succeed(FileConsumer1(self.fObj))
def close(self):
return defer.succeed(None)
class FTPShell1(FTPShell):
def openForWriting(self, path):
p = self._path(path)
if p.isdir():
return defer.fail(IsADirectoryError(path))
try:
fObj = p.open('w')
except (IOError, OSError), e:
return errnoToFailure(e.errno, path)
except:
return defer.fail()
return defer.succeed(FileWriter1(fObj))
class FTPRealm1(object):
def __init__(self, root):
self.path = filepath.FilePath(root)
def requestAvatar(self, avatarId, mind, *interfaces):
avatar = FTPShell1(self.path)
return (IFTPShell, avatar, getattr(avatar, 'logout', lambda: None))
p = Portal(FTPRealm1('./'), [ AllowAnonymousAccess() ])
f = FTPFactory(p)
reactor.listenTCP(4021, f)
reactor.run()
clearly the check if size > 10 will be bigger, but how should a be indicating there's a problem at this point? As it stands, twisted catches that exception, but it's not very elegant. As far as I can see from examination of ftp.py there's nothing obvious I can return here. Can I pass down a deferred in some way? How should I be closing down the transfer elegantly?
Thanks,
Here's a revised version
#!/usr/bin/python
import os
from zope.interface import Interface, implements
from twisted.protocols.ftp import FTPFactory, FTPShell, FTPAnonymousShell, IFTPShell, IWriteFile , BaseFTPRealm, FTPCmdError, EXCEEDED_STORAGE_ALLOC
from twisted.cred.portal import Portal
from twisted.cred.checkers import AllowAnonymousAccess
from twisted.internet import reactor, defer, interfaces
from twisted.python import filepath
class ExceededStorageAllocError(FTPCmdError):
errorCode = EXCEEDED_STORAGE_ALLOC
class FileConsumer(object):
implements(interfaces.IConsumer)
def __init__(self):
self.data = ""
self.error = None
def registerProducer(self, producer, streaming):
self.producer = producer
assert streaming
def unregisterProducer(self):
if self.producer:
self.producer.stopProducing()
self.producer = None
def write(self, bytes):
self.data += bytes
if len(self.data) > 10:
self.unregisterProducer()
self.error = ExceededStorageAllocError()
class FileWriter(object):
implements(IWriteFile)
def __init__(self, path):
self.path = path
def receive(self):
self.consumer = FileConsumer()
return defer.succeed(self.consumer)
def close(self):
if self.consumer.error:
return defer.fail(self.consumer.error)
try:
f = self.path.open('w')
except (IOError, OSError), e:
return errnoToFailure(e.errno, path)
f.write(self.consumer.data)
return defer.succeed(None)
class FTPShell1(FTPShell):
makeDirectory = FTPAnonymousShell.makeDirectory
removeDirectory = FTPAnonymousShell.removeDirectory
def openForWriting(self, path):
p = self._path(path)
if p.isdir():
return defer.fail(IsADirectoryError(path))
return defer.succeed(FileWriter(p))
class FTPRealm1(BaseFTPRealm):
def __init__(self, root):
self.root = root
def requestAvatar(self, avatarId, mind, *interfaces):
avatar = FTPShell1(filepath.FilePath(self.root))
return (IFTPShell, avatar, getattr(avatar, 'logout', lambda: None))
p = Portal(FTPRealm1('./'), [ AllowAnonymousAccess() ])
f = FTPFactory(p)
reactor.listenTCP(4021, f)
reactor.run()
which accumulates the received data within the FileConsumer() then aborts if the file is too long. the close() method of the FileWriter() then either reports that error or writes the complete buffer to the file.
The only real issue I'm having with this is that when run, the exception is displayed on the server:
Unexpected error received during transfer:
Traceback (most recent call last):
Failure: __main__.ExceededStorageAllocError:
As a quick disclaimer, I'm very bad with Twisted's producer/consumer model, so this may not work. As always, I'm not responsible if things blow up ;)
You seem to be on the correct path so pat yourself on the back for that. I think if you call unregisterProducer when a file is too large, the file should stop consuming. You may also need to call self.producer.stopProducing(), but don't quote me on that.
def unregisterProducer(self):
self.producer.stopProducing()
self.fObj.close()
def write(self, bytes):
size = os.fstat(self.fObj.fileno()).st_size + len(bytes)
if size > 10:
self.unregisterConsumer()
# log statements would go here
# do some clean up too
self.fObj.write(bytes)
If my mental code Python interpreter is correct, this should simply just stop consuming the file. As far as what you should return to the client, you're going to have to read the RFC about FTP to figure that out.
PS
As tedious as it may seem, please use the #implementor decorators. Most times you'll be fine, but there may be instances where unexpected trace backs appear.

How to check if a file is already opened (in the same process)

And I'd like to specifically achieve that with the try catch construct.
This related question suggests that I can do:
try:
open(fileName, 'wb+')
except:
print("File already opened!")
raise
However, it doesn't work me. I can open the same file multiple times without any problem:
fileObj1 = open(fileName, 'wb+')
fileObj2 = open(fileName, 'wb+')
Is it because I have Python 3.5? Or because I'm using Raspbian?
Thanks for the help!
You should open the same file but assign them to different variables, like so:
file_obj = open(filename, "wb+")
if not file_obj.closed:
print("File is already opened")
The .closed only checks if the file has been opened by the same Python process.
I would suggest using something like this
# Only works on Windows
def is_open(file_name):
if os.path.exists(file_name):
try:
os.rename(file_name, file_name) #can't rename an open file so an error will be thrown
return False
except:
return True
raise NameError
Edited to fit the OP's specific issues
class FileObject(object):
def __init__(self, file_name):
self.file_name = file_name
self.__file = None
self.__locked = False
#property
def file(self):
return self.__file
#property
def locked(self):
return self.__locked
def open(self, mode, lock=True):#any testing on file should go before the if statement such as os.path.exists()
#replace mode with *args if you want to pass multiple modes
if not self.locked:
self.__locked = lock
self.__file = open(self.file_name, mode)
return self.file
else:
print 'Cannot open file because it has an exclusive lock placed on it'
return None #do whatever you want to do if the file is already open here
def close(self):
if self.file != None:
self.__file.close()
self.__file = None
self.__locked = False
def unlock(self):
if self.file != None:
self.__locked = False

PyQt program randomly not responding without a Traceback

I wrote a program to batch change the filenames of many pictures, using PyQt5.
When I run it, it runs through some pictures successfully, and randomly crash without a Python Traceback, showing "has stopped working" in windows 8.1. Even if I use the same testcases, the program will sometimes crash after 20+ pictures, sometimes only 2, sometimes runs to the end.
I don't even know the program crashed in which line. How do I solve this problem?
Here is the program, I minimized the code that still work, and randomly crash as before.
# -*- coding: utf-8 -*-
import sys
import os
import re
from PyQt5 import Qt
if __name__ == '__main__':
application_Variable = Qt.QApplication(sys.argv)
from MainWindow import Ui_MainWindow_Widget
from FileName import Ui_FileName_Widget
class filename_class: # just a class to get path, filename, append
def __init__(self, fullpath):
self.re_path_temp = re.match(r".+/", fullpath)
self.path = self.re_path_temp.group(0)
self.name = fullpath[len(self.path):]
self.append = self.name[len(self.name[:self.name.rfind('.')])-len(self.name)+1:]
class fileNameDefine_Widget(Qt.QWidget): # the rename widget
def __init__(self, filename):
super(fileNameDefine_Widget, self).__init__()
self.fileWidget = Ui_FileName_Widget()
self.fileWidget.setupUi(self)
self.filename = filename
self.file_append = filename_class(self.filename).append # get the append
self.fileWidget.InputFileName_LineEdit.textChanged.connect(self.input_file_name_Change)
def input_file_name_Change(self):
self.export_name = self.fileWidget.InputFileName_LineEdit.text() + "." + self.file_append
self.fileWidget.ExportFileName_LineEdit.setText(self.export_name)
self.fileWidget.InputFileName_LineEdit.setEnabled(True)
class MainWindow_Class(Qt.QWidget): # the main widget
def __init__(self):
super(MainWindow_Class, self).__init__()
self.main = Ui_MainWindow_Widget() # init
self.main.setupUi(self)
self.root_directory = r"D:\TLCTest"
self.file_list = Qt.QFileDialog.getOpenFileNames(caption="Select file", directory=self.root_directory)[0]
self.count = 0 # count which file are being processed
self.show()
self.initiate_change_filename()
def initiate_change_filename(self):
file = self.file_list[self.count]
# show the picture
self.pixmap = Qt.QPixmap()
self.pixmap.load(file)
self.graphicsPixmapItem = Qt.QGraphicsPixmapItem(self.pixmap)
self.graphicsScene = Qt.QGraphicsScene()
self.graphicsScene.addItem(self.graphicsPixmapItem)
self.main.graphicsView.setScene(self.graphicsScene)
# start the rename widget
self.fileName_Widget = fileNameDefine_Widget(file)
self.fileName_Widget.fileWidget.InputFileName_LineEdit.returnPressed.connect(self.submit) # press enter to submit
self.fileName_Widget.show()
def submit(self):
filename = self.fileName_Widget.filename
path = filename_class(filename).path
final_name = self.fileName_Widget.fileWidget.ExportFileName_LineEdit.text()
os.rename(filename, path + final_name)
self.count += 1
if self.count == len(self.file_list):
exit()
else:
self.fileName_Widget.close()
self.initiate_change_filename()
if __name__ == '__main__':
my_Qt_Program = MainWindow_Class()
my_Qt_Program.show()
sys.exit(application_Variable.exec_())
As ekhumoro's comment, this problem was caused by repeatedly creating a fileNameDefine_Widget object like:
def initiate_change_filename(self):
self.fileName_Widget = fileNameDefine_Widget(file)
Instead, one should create this object once, and init it every time required, like:
class TLC_processor_Class(Qt.QWidget):
def init(self):
# Blabla
self.fileName_Widget = fileNameDefine_Widget(file)
def initiate_change_filename(self):
self.fileName_Widget.__init__(file)

Categories