Python, how to keep program going after exception is caught - python

probably a simple question as I fairly new to python and programming in general but I am currently working on improving a program of mine and can't figure out how to keep the program going if an exception is caught. Maybe I am looking at it the wrong way but for example I have something along these lines:
self.thread = threading.Thread(target=self.run)
self.thread.setDaemon(True)
self.thread.start()
def run(self):
logging.info("Starting Awesome Program")
try:
while 1:
awesome_program(self)
except:
logging.exception('Got exception on main handler')
OnError(self)
def OnError(self):
self.Destroy()
Obviously I am currently just killing the program when an error is reached. awesome_program is basically using pyodbc to connect and run queries on a remote database. The problem arises when connection is lost. If I don't catch the exceptions the program just freezes so I set it up as it is above which kills the program but this is not always ideal if no one is around to manually restart it. Is there an easy way to either keep the program running or restert it. Feel free to berate me for incorrect syntax or poor programming skills. I am trying to teach myself and am still very much a novice and there is plenty I don't understand or am probably not doing correctly. I can post more of the code if needed. I wasn't sure how much to post without being overwhelming.

Catch the exception within the loop, and continue, even if an exception is caught.
def run(self):
logging.info("Starting Awesome Program")
while 1:
try:
awesome_program(self)
except:
logging.exception('Got exception on main handler')
OnError(self)
BTW:
Your indentation seems messed up.
I'd prefer while True. Python has bool type, unlike C, so when a bool is expected - give while a bool.

You're looking for this:
def run(self):
while True:
try:
do_things()
except Exception as ex:
logging.info("Caught exception {}".format(ex))

Take a look at Python Exception Handling, and in particular Try...Except. It will allow you to catch particular errors and handle them however you choose fit, even ignore them completely, if possible. For example:
try:
while something == True:
do_stuff()
except ExceptionType:
print "Something bad happened!" #An error occurred, but the script continues
except:
print "Something worse happened!"
raise #a worse error occurred, now we kill it
do_more_stuff()

Related

Do something specific if python scripts exits because of error

My script sometimes errors which is fine, but I have to manually restart the script.
Anyone knows how to make it so that it actually works infinitely even if it crashed 50 times, currently what I have only works for 1 crash.
try:
while True:
do_main_logic()
except:
continue
I have tried many scripts, but I am expecting it to just continue no matter what.
Wrap only do_main_logic() in a try-except block, not the full loop.
while True:
try:
do_main_logic()
except:
pass
Caveat: Catching bare exceptions is frowned upon for good reason. It would be better if you could specify the type(s) of exceptions you expect. To cite the Programming Recommendations in the Style Guide for Python Code:
When catching exceptions, mention specific exceptions whenever possible instead of using a bare except: clause.
A bare except: clause will catch SystemExit and KeyboardInterrupt exceptions, making it harder to interrupt a program with Control-C, and can disguise other problems. If you want to catch all exceptions that signal program errors, use except Exception: (bare except is equivalent to except BaseException:).
You want to do it forever ?
Just add a while :)
while True:
try:
while True:
do_main_logic()
except:
continue

Unable to KeyboardInterrupt while loop

I have a python script that runs on an infinite loops. In the loop multiprocess and async functions happen so normally I catch KeyboardInterrupt to properly kill all the processes.
Using similar code somehow on one of the loops I am unable to catch the KeyboardInterrupt the loop just keeps going.
logic goes like that:
try:
while True:
do stuff
except (KeyboardInterrupt, SystemExit):
exit cleanly
Normally I would suspect a blanket try ... except somewhere in the children functions but I went over the whole code base and while there is a lot of error catching everything is specific.
Is there a way to trace errors and somehow figure out where the KeyboardInterrupt is caught ?
Thank you
****** Edit after some debugging...
So I disabled the code part by part until I cornered the bug:
Somewhere in the code I was calling a method that was missing self and was not marked as #staticmethod.
Changing that fixed my issue.
This works for me.
try:
while True:
print(1)
except KeyboardInterrupt:
raise
EDIT:
Actually read your question, I won't be able to tell you why it's not raising an error without seeing the rest or more of the code.

Is it possible to create never crashing python code with exception handling?

I wonder if the below python code (specifically http server) ever crashes? Assuming that there is no grammer error in any of the library code(already compiled), what I think that handling the exceptions in a while loop should be sufficient for this code not to crash anytime. I tried the below code for a while and never crashed, but I wonder if theoretically or practically possible for this program to crash?
while True:
try:
server = HTTPServer(('', PORT_NUMBER), myHandler)
server.serve_forever()
except:
try:
server.socket.close()
except:
pass
The actual reason I am asking this question that I don't want to deal with UNIX staff to watch the process and restart it if it crashes. Is the above solution sufficient?
Thanks.
If "except" block has worng code, it can crash cause of it. I mean, something like that:
# path/to/py3
FOO = [1,2,3]
try:
# index out of bound, try block has error, so it goes ahead and executes except-block
print(FOO[4])
except:
# if there is some kind of error, like Syntax error, program can crash
print "Index out of bound!"
print("2"+2)
print(FOO["BAR"])
but if exception block has the correct logic too, then programm should work without crashing
Like Klaus D. already mentioned in his comment, there can be cases where the socket close code in your except block crashes. You could optionally also throw a try except around that as well...
Another option is to use something like this (no UNIX involved):
http://supervisord.org/
It's easy to run and will automatically restart your program if it crashes.

Python3: purge exception chain?

I'm trying to raise an exception within an except: block but the interpreter tries to be helpful and prints stack traces 'by force'. Is it possible to avoid this?
A little bit of background information:
I'm toying with urwid, a TUI library for python. The user interface is started by calling urwid.MainLoop.run() and ended by raising urwid.ExitMainLoop(). So far this works fine but what happens when another exception is raised? E.g. when I'm catching KeyboardInterrupt (the urwid MainLoop does not), I do some cleanup and want to end the user interface - by raising the appropriate exception. But this results in a screen full of stack traces.
Some little research showed python3 remembers chained exceptions and one can explicitly raise an exception with a 'cause': raise B() from A(). I learned a few ways to change or append data regarding the raised exceptions but I found no way to 'disable' this feature. I'd like to avoid the printing of stack traces and lines like The above exception was the direct cause of... and just raise the interface-ending exception within an except: block like I would outside of one.
Is this possible or am I doing something fundamentally wrong?
Edit:
Here's an example resembling my current architecture, resulting in the same problem:
#!/usr/bin/env python3
import time
class Exit_Main_Loop(Exception):
pass
# UI main loop
def main_loop():
try:
while True:
time.sleep(0.1)
except Exit_Main_Loop as e:
print('Exit_Main_Loop')
# do some UI-related clean up
# my main script
try:
main_loop()
except KeyboardInterrupt as e:
print('KeyboardInterrupt')
# do some clean up
raise Exit_Main_Loop() # signal the UI to terminate
Unfortunately I can't change main_loop to except KeyboardInterrupt as well. Is there a pattern to solve this?
I still don't quite understand your explanation, but from the code:
try:
main_loop()
except KeyboardInterrupt as e:
print('KeyboardInterrupt')
# do some clean up
raise Exit_Main_Loop() # signal the UI to terminate
There is no way that main_loop could ever see the Exit_Main_Loop() exception. By the time you get to the KeyboardInterrupt handle, main_loop is guaranteed to have already finished (in this case, because of an unhandled KeyboardInterrupt), so its exception handler is no longer active.
So, what happens is that you raise a new exception that nobody catches. And when an exception gets to the top of your code without being handled, Python handles it automatically by printing a traceback and quitting.
If you want to convert one type of exception into another so main_loop can handle it, you have to do that somewhere inside the try block.
You say:
Unfortunately I can't change main_loop to except KeyboardInterrupt as well.
If that's true, there's no real answer to your problem… but I'm not sure there's a problem in the first place, other than the one you created. Just remove the Exit_Main_Loop() from your code, and isn't it already doing what you wanted? If you're just trying to prevent Python from printing a traceback and exiting, this will take care of it for you.
If there really is a problem—e.g., the main_loop code has some cleanup code that you need to get executed no matter what, and it's not getting executed because it doesn't handle KeyboardInterrupt—there are two ways you could work around this.
First, as the signal docs explain:
The signal.signal() function allows to define custom handlers to be executed when a signal is received. A small number of default handlers are installed: … SIGINT is translated into a KeyboardInterrupt exception.
So, all you have to do is replace the default handler with a different one:
def handle_sigint(signum, frame):
raise ExitMainLoop()
signal.signal(signal.SIGINT, handle_sigint)
Just do this before you start main_loop, and you should be fine. Keep in mind that there are some limitations with threaded programs, and with Windows, but if none of those limitations apply, you're golden; a ctrl-C will trigger an ExitMainLoop exception instead of a KeyboardInterrupt, so the main loop will handle it. (You may want to also add an except ExitMainLoop: block in your wrapper code, in case there's an exception outside of main_loop. However, you could easily write a contextmanager that sets and restores the signal around the call to main_loop, so there isn't any outside code that could possibly raise it.)
Alternatively, even if you can't edit the main_loop source code, you can always monkeypatch it at runtime. Without knowing what the code looks like, it's impossible to explain exactly how to do this, but there's almost always a way to do it.

Python Ignore Exception and Go Back to Where I Was

I know using below code to ignore a certain exception, but how to let the code go back to where it got exception and keep executing? Say if the exception 'Exception' raises in do_something1, how to make the code ignore it and keep finishing do_something1 and process do_something2? My code just go to finally block after process pass in except block. Please advise, thanks.
try:
do_something1
do_something2
do_something3
do_something4
except Exception:
pass
finally:
clean_up
EDIT:
Thanks for the reply. Now I know what's the correct way to do it. But here's another question, can I just ignore a specific exception (say if I know the error number). Is below code possible?
try:
do_something1
except Exception.strerror == 10001:
pass
try:
do_something2
except Exception.strerror == 10002:
pass
finally:
clean_up
do_something3
do_something4
There's no direct way for the code to go back inside the try-except block. If, however, you're looking at trying to execute these different independant actions and keep executing when one fails (without copy/pasting the try/except block), you're going to have to write something like this:
actions = (
do_something1, do_something2, #...
)
for action in actions:
try:
action()
except Exception, error:
pass
update. The way to ignore specific exceptions is to catch the type of exception that you want, test it to see if you want to ignore it and re-raise it if you dont.
try:
do_something1
except TheExceptionTypeThatICanHandleError, e:
if e.strerror != 10001:
raise
finally:
clean_up
Note also, that each try statement needs its own finally clause if you want it to have one. It wont 'attach itself' to the previous try statement. A raise statement with nothing else is the correct way to re-raise the last exception. Don't let anybody tell you otherwise.
What you want are continuations which python doesn't natively provide. Beyond that, the answer to your question depends on exactly what you want to do. If you want do_something1 to continue regardless of exceptions, then it would have to catch the exceptions and ignore them itself.
if you just want do_something2 to happen regardless of if do_something1 completes, you need a separate try statement for each one.
try:
do_something1()
except:
pass
try:
do_something2()
except:
pass
etc. If you can provide a more detailed example of what it is that you want to do, then there is a good chance that myself or someone smarter than myself can either help you or (more likely) talk you out of it and suggest a more reasonable alternative.
This is pretty much missing the point of exceptions.
If the first statement has thrown an exception, the system is in an indeterminate state and you have to treat the following statement as unsafe to run.
If you know which statements might fail, and how they might fail, then you can use exception handling to specifically clean up the problems which might occur with a particular block of statements before moving on to the next section.
So, the only real answer is to handle exceptions around each set of statements that you want to treat as atomic
you could have all of the do_something's in a list, and iterate through them like this, so it's no so wordy. You can use lambda functions instead if you require arguments for the working functions
work = [lambda: dosomething1(args), dosomething2, lambda: dosomething3(*kw, **kwargs)]
for each in work:
try:
each()
except:
pass
cleanup()
Exceptions are usually raised when a performing task can not be completed in a manner intended by the code due to certain reasons. This is usually raised as exceptions. Exceptions should be handled and not ignored. The whole idea of exception is that the program can not continue in the normal execution flow without abnormal results.
What if you write a code to open a file and read it? What if this file does not exist?
It is much better to raise exception. You can not read a file where none exists. What you can do is handle the exception, let the user know that no such file exists. What advantage would be obtained for continuing to read the file when a file could not be opened at all.
In fact the above answers provided by Aaron works on the principle of handling your exceptions.
I posted this recently as an answer to another question. Here you have a function that returns a function that ignores ("traps") specified exceptions when calling any function. Then you invoke the desired function indirectly through the "trap."
def maketrap(*exceptions):
def trap(func, *args, **kwargs):
try:
return func(*args, **kwargs)
except exceptions:
return None
return trap
# create a trap that ignores all exceptions
trapall = maketrap(Exception)
# create a trap that ignores two exceptions
trapkeyattrerr = maketrap(KeyError, AttributeError)
# Now call some functions, ignoring specific exceptions
trapall(dosomething1, arg1, arg2)
trapkeyattrerr(dosomething2, arg1, arg2, arg3)
In general I'm with those who say that ignoring exceptions is a bad idea, but if you do it, you should be as specific as possible as to which exceptions you think your code can tolerate.
Python 3.4 added contextlib.suppress(), a context manager that takes a list of exceptions and suppresses them within the context:
with contextlib.suppress(IOError):
print('inside')
print(pathlib.Path('myfile').read_text()) # Boom
print('inside end')
print('outside')
Note that, just as with regular try/except, an exception within the context causes the rest of the context to be skipped. So, if an exception happens in the line commented with Boom, the output will be:
inside
outside

Categories