Reputation: 3682
To figure out what it would take to avoid some recursion, I need to catch any exception (edit: Not just ones derived from Exception, but all exceptions, including KeyboardInterrupt and user exceptions), put it in a variable, and later re-raise it outside the catch block. Essentially, I'm trying to roll my own finally block. Is this possible?
The actual problem is to call a number of cleanup functions, and if any of them fail, all the others should also be called, then the exception for the one that failed should still propagate. Here's my current solution, it takes a list of Popen objects:
def cleanupProcs(procs):
if not procs:
return
proc = procs.pop(0)
try:
proc.terminate()
proc.wait()
finally:
cleanupProcs(procs)
Is there an iterative way to do this? A more elegant way? A more Pythonic way?
Upvotes: 15
Views: 19898
Reputation: 27423
If you want the stacktrace included:
try:
# something
except:
the_type, the_value, the_traceback = sys.exc_info()
later
raise the_type, the_value, the_traceback
(Related to this answer)
See also here for Python 2.7.
Upvotes: 15
Reputation: 17188
I'd probably use BaseException
to catch anything that gets thrown, and iterate through all your cleanup functions (instead of using recursion). Then append any exceptions to a list, to deal with (re-raise, log, etc) as appropriate when you finish the cleanup.
def runCleanup(procs):
exceptions = []
for proc in procs:
try:
proc.terminate()
proc.wait()
except BaseException as e:
exceptions.append(e) # Use sys.exc_info() for more detail
return exceptions # To be handled or re-raised as needed
Upvotes: 3
Reputation: 1833
Thats easy:
>>> try:
... #something
... except BaseException, e: # OK. Using BaseException instead of Exception
... pass
...
>>>
>>> raise e
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'x' is not defined
>>>
Upvotes: 0
Reputation: 51847
In this case, I think I would argue that you may not be doing it right.
To me, the point of an exception is to signal a bum bum baaaaa exceptional circumstance. And when you are writing code that may fire an exception you have two responsible options - catch it and do something with it (like recover), or completely ignore it.
From what you say in your post, you don't really care that an exception happened. It shouldn't halt your program, and program flow should continue as normal. You do however want to know that an exception happened. And this is where the logging module comes in:
import logging
log = logging
def get_some_cheese():
raise ValueError("Sorry, we're right out.")
try:
get_some_cheese()
except:
log.exception("What a waste of life")
When you log an exception it automagically adds stack trace information for you. After you config your logging a bit, you can get it setup to do all sorts of whatever things you want to do - send an email, write to a file or stdout/err, whatever. But then you'll get informed that an exception occured, but you can also simply recover from the error and continue on your merry way cleaning up whatever it is you need to clean up.
Upvotes: 4
Reputation: 12401
you can use:
procexceptions = []
except Exception, e:
procexceptions.append(e)
and then later (after the loop for terminating processes) you can
raise procexceptions[0]
etc.
Upvotes: 1
Reputation: 21976
Like just about everything else in Python, exceptions are objects and therefore can be bound to names and operated upon. Here's a short example showing how to grab an exception and use it later:
>>> def to_int(x):
... try:
... return int(x)
... except Exception, e:
... print 'in exception block:', e
... print 'after exception block:', e
>>> to_int('12')
12
>>> to_int('abc')
in exception block: invalid literal for int() with base 10: 'abc'
after exception block: invalid literal for int() with base 10: 'abc'
Upvotes: 0
Reputation: 34185
Openstack does something very similar for a different reason. Have a look at https://github.com/openstack/nova/blob/master/nova/openstack/common/excutils.py#L30 (function save_and_reraise_exception
). In their case it works like a resource manager.
Upvotes: 0