do not continue when exception - python

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()

Related

Catch any excpetion to avoid memory leak - Python bad/good pratices

I want to make sure a method is called if any exception is raised. In this situation, is it ok (good/bad practices or may lead to unexpected consequences) to try/except any Exception? Here's an example of what's on my mind using a decorator:
# implementation
import sys
import traceback
class AmazingClass:
def __init__(self, arg=None):
self.__att = arg
#property
def att(self, ):
return self.__att
def make_sure_it_quits(method):
def inner(self, *args, **kwargs):
try:
return method(self, *args, **kwargs)
except Exception as err:
print(err, "- This was caught because it couldn't be foreseen.")
traceback.print_exc()
print("\nQuitting what is suppose to be quited...")
self.quit()
return inner
#make_sure_it_quits
def this_may_raise_errors(self, arg):
try:
self.__att += arg
except TypeError as err:
print("This I can handle! Cleaning and exiting...")
self.quit()
# sys.exit(1) # exit, if it's the case
def quit(self, ):
self.__arg = None
print("Everything is very clean now!")
# examples
def no_errors():
obj = AmazingClass("test")
obj.this_may_raise_errors("_01")
print(obj.att)
def with_error_01():
obj = AmazingClass("test")
obj.this_may_raise_erros(1)
print(obj.att)
def with_error_02():
obj = AmazingClass("test")
obj.this_may_raise_errors()
print(obj.att)
# main
if __name__ == '__main__':
no_errors()
with_error_01()
with_error_02()
In this case, with_error_01 represents situations I know in advance that can happen, while with_error_02 is an unexpected use of the class.
In both cases, the use of traceback shows what and where went wrong. Also, the method quit must always be called in case of any error.

Passing methods into methods Python

I have a class in python. What I am trying to achieve is to pass one method into another. Say I have a method that is scanning for directories on a page and another method that opens the wordlist for which it will format all the words to pass into the method that is scanning the directories.
My issue is that the method that is formatting the words by stripping them, is not being passed into the method that is scanning directories.
class exampleClass:
def __init__(self):
pass
def openWordlist(self):
try:
with open(wordlist, 'r') as file:
for word in file:
word = word.strip()
except FileNotFoundError:
print('File does not exist')
def scanDomain(self):
try:
domain = 'http://' + targetURL + '/' + word
r = requests.get(domain)
if r.status_code == 200:
print(f'[+] {domain}')
else:
if isVerbose:
print(f'[~] {domain}')
if r.status_code == 200:
print(f'[+] {domain}')
except requests.exceptions.ConnectionError:
print('[!] CONNECTION ERROR! Exiting...')
sys.exit(0)
if __name__ == '__main__':
obj = exampleClass()
obj.openWordlist()
obj.scanDomain()
My goal is to pass the method openWordlist() to the scanDomain() method so it gets to read that wordlist and parse each request.
To call a method inside another method, you can call it using the self argument (which represents your class inside its methods).
class MyClass:
def __init__(self):
pass
def foo(self):
return True
def bar(self):
res = self.foo()
return res
It's not clear from your example how openWordlist and scanDomain are supposed to interact. I infer from the shared variable word that it is supposed to be shared between the two methods. A good way to do this is to make word an attribute of the class instance.
class exampleClass:
def __init__(self):
self.words = None
self.targetURL = ""
def openWordlist(self, wordlist):
try:
with open(wordlist, 'r') as file:
self.words = [word.strip() for word in file]
except FileNotFoundError:
print('File does not exist')
def scanDomain(self):
for word in self.words:
domain = 'http://' + self.targetURL + '/' + word
try:
r = requests.get(domain)
except requests.exceptions.ConnectionError:
print('[!] CONNECTION ERROR! Exiting...')
continue
if r.status_code == 200:
print(f'[+] {domain}')
else:
if isVerbose:
print(f'[~] {domain}')
I'm not sure if it is what you want, but you can simply add an argument to the function that should receive the other function, and then execute the function that was passed like this:
class exampleClass():
def openWordList(self):
print("Do something else")
def scanDomain(self, a_function):
print("Do something")
a_function()
if __name__ == "__main__":
obj = exampleClass()
obj.scanDomain(obj.openWordList)

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

Opening multiple (an unspecified number) of files at once and ensuring they are correctly closed

I am aware that I can open multiple files with something like,
with open('a', 'rb') as a, open('b', 'rb') as b:
But I have a situation where I have a list of files to open and am wondering what the preferred method is of doing the same when the number of files is unknown in advance. Something like,
with [ open(f, 'rb') for f in files ] as fs:
(but this fails with an AttributeError since list doesn't implement __exit__)
I don't mind using something like,
try:
fs = [ open(f, 'rb') for f in files ]
....
finally:
for f in fs:
f.close()
But am not sure what will happen if some files throw when trying to open them. Will fs be properly defined, with the files that did manage to open, in the finally block?
No, your code wouldn't initialise fs unless all open() calls completed successfully. This should work though:
fs = []
try:
for f in files:
fs.append(open(f, 'rb'))
....
finally:
for f in fs:
f.close()
Note also that f.close() could fail so you may want to catch and ignore (or otherwise handle) any failures there.
Sure, why not, Here's a recipe that should do it. Create a context manager 'pool' that can enter an arbitrary number of contexts (by calling it's enter() method) and they will be cleaned up at the end of the end of the suite.
class ContextPool(object):
def __init__(self):
self._pool = []
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, exc_tb):
for close in reversed(self._pool):
close(exc_type, exc_value, exc_tb)
def enter(self, context):
close = context.__exit__
result = context.__enter__()
self._pool.append(close)
return result
For example:
>>> class StubContextManager(object):
... def __init__(self, name):
... self.__name = name
... def __repr__(self):
... return "%s(%r)" % (type(self).__name__, self.__name)
...
... def __enter__(self):
... print "called %r.__enter__()" % (self)
...
... def __exit__(self, *args):
... print "called %r.__exit__%r" % (self, args)
...
>>> with ContextPool() as pool:
... pool.enter(StubContextManager("foo"))
... pool.enter(StubContextManager("bar"))
... 1/0
...
called StubContextManager('foo').__enter__()
called StubContextManager('bar').__enter__()
called StubContextManager('bar').__exit__(<type 'exceptions.ZeroDivisionError'>, ZeroDivisionError('integer division or modulo by zero',), <traceback object at 0x02958648>)
called StubContextManager('foo').__exit__(<type 'exceptions.ZeroDivisionError'>, ZeroDivisionError('integer division or modulo by zero',), <traceback object at 0x02958648>)
Traceback (most recent call last):
File "<pyshell#67>", line 4, in <module>
1/0
ZeroDivisionError: integer division or modulo by zero
>>>
Caveats: context managers aren't supposed to raise exceptions in their __exit__() methods, but if they do, this recipe doesn't do the cleanup for all the context managers. Similarly, even if every context manager indicates that an exception should be ignored (by returning True from their exit methods), this will still allow the exception to be raised.
The class ExitStack from the contextlib module provides the functionality you are looking for.
The canonical use-case that is mentioned in the documentation is managing a dynamic number of files.
with ExitStack() as stack:
files = [stack.enter_context(open(fname)) for fname in filenames]
# All opened files will automatically be closed at the end of
# the with statement, even if attempts to open files later
# in the list raise an exception
Errors can occur when attempting to open a file, when attempting to read from a file, and (very rarely) when attempting to close a file.
So a basic error handling structure might look like:
try:
stream = open(path)
try:
data = stream.read()
finally:
stream.close()
except EnvironmentError as exception:
print 'ERROR:', str(exception)
else:
print 'SUCCESS'
# process data
This ensures that close will always be called if the stream variable exists. If stream doesn't exist, then open must have failed, and so there is no file to close (in which case, the except block will be executed immediately).
Do you really need to have the files open in parallel, or can they be processed sequentially? If the latter, then something like the above file-processing code should be put in a function, which is then called for each path in the list.
Thanks for all your answers. Taking inspiration from all of you, I have come up with the following. I think (hope) it works as I intended. I wasn't sure whether to post it as an answer or an addition to the question, but thought an answer was more appropriate as then if it fails to do what I'd asked it can be commented on appropriately.
It can be used for example like this ..
with contextlist( [open, f, 'rb'] for f in files ) as fs:
....
or like this ..
f_lock = threading.Lock()
with contextlist( f_lock, ([open, f, 'rb'] for f in files) ) as (lock, *fs):
....
And here it is,
import inspect
import collections
import traceback
class contextlist:
def __init__(self, *contexts):
self._args = []
for ctx in contexts:
if inspect.isgenerator(ctx):
self._args += ctx
else:
self._args.append(ctx)
def __enter__(self):
if hasattr(self, '_ctx'):
raise RuntimeError("cannot reenter contextlist")
s_ctx = self._ctx = []
try:
for ctx in self._args:
if isinstance(ctx, collections.Sequence):
ctx = ctx[0](*ctx[1:])
s_ctx.append(ctx)
try:
ctx.__enter__()
except Exception:
s_ctx.pop()
raise
return s_ctx
except:
self.__exit__()
raise
def __exit__(self, *exc_info):
if not hasattr(self, '_ctx'):
raise RuntimeError("cannot exit from unentered contextlist")
e = []
for ctx in reversed(self._ctx):
try:
ctx.__exit__()
except Exception:
e.append(traceback.format_exc())
del self._ctx
if not e == []:
raise Exception('\n> '*2+(''.join(e)).replace('\n','\n> '))

Categories