Say I have some code like this:
try:
try:
raise Exception("in the try")
finally:
raise Exception("in the finally")
except Exception, e:
print "try block failed: %s" % (e,)
The output is:
try block failed: in the finally
From the point of that print statement, is there any way to access the exception raised in the try, or has it disappeared forever?
NOTE: I don't have a use case in mind; this is just curiosity.
I can't find any information about whether this has been backported and don't have a Py2 installation handy, but in Python 3, e has an attribute called e.__context__, so that:
try:
try:
raise Exception("in the try")
finally:
raise Exception("in the finally")
except Exception as e:
print(repr(e.__context__))
gives:
Exception('in the try',)
According to PEP 3314, before __context__ was added, information about the original exception was unavailable.
try:
try:
raise Exception("in the try")
except Exception, e:
print "try block failed"
finally:
raise Exception("in the finally")
except Exception, e:
print "finally block failed: %s" % (e,)
However, It would be a good idea to avoid having code that is likely to throw an exception in the finally block - usually you just use it to do cleanup etc. anyway.
Related
I know I can store an exception name in a variable with this syntax:
try:
code
except TypeError as e:
logger.error(e)
except NameError as e:
logger.error(e)
How do I do the same for the generic except: message? I assume that this (which is the general idea) won't work:
try:
code
except as e:
logger.error(e)
You can you use type(e).__name__ to capture the name of any error you encounter, and access the message as you a normal variable, with e.message. All the built in errors (indexError, TypeError, etc.) are children of the class Exception, so they will be picked up. to save it as a variable named 'err':
try:
code
except Exception as e:
err = type(e).__name__
message = e.message
This will save the error type of any exception of the base python type Exception that you run into, using the built in __name__ variable
BaseException is the broadest type you can catch:
try:
# some code
except BaseException as e:
logger.error(e)
You are able to catch Exception:
import logging
try:
code
except TypeError as e:
logger.error(e)
except NameError as e:
logger.error(e)
except Exception as e:
logging.error(e)
I ran into this with Python 2, where old-style classes aren't caught by except Exception or except BaseException. I solved it by using sys.exc_info to access the current exception:
import sys
try:
code
except:
e = sys.exc_info()[1]
logging.error(e)
I have somthing similar in my code below, where I have multiple except statements and all of them have to execute the someCleanUpCode() function. I was wondering if there is a shorter way to do it. Like a block that is only being executed when there was an exception. I can't use the finally block because that's also being executed when the try doesn't raise an error. And I only need to execute the someCleanUpCode() when there was an error. I first want to print the error and after that, run the someCleanUpCode()
try:
dangerousCode()
except CalledProcessError:
print "There was an error without a message"
someCleanUpCode()
except Exception as e:
print "There was an error: " +repr(e)
someCleanUpCode()
Assuming CalledProcessorError subclasses Exception (which should be the case):
try:
dangerous_code()
except Exception as e:
print "There was an error %s" % ("without an error" if isinstance(e, CalledProcessError) else repr(e))
some_cleanup_code()
or if you have more to do:
try:
dangerous_code()
except Exception as e:
try:
dangerous_code()
except Exception as e:
if isinstance(e, CalledProcessError):
print "There was an error without a message"
else:
print "There was an error: " +repr(e)
some_cleanup_code()
are you looking for something like this?
try:
1/0
except (ValueError, ZeroDivisionError) as e:
print e
# add some cleanup code here
>>>integer division or modulo by zero
This catches multiple exceptions
I try to construct a except clause that catches everything except [sic] a particular type of exception:
try:
try:
asdjaslk
except not NameError as ne: #I want this block to catch everything except NameError
print("!NameError- {0}: {1}".format(ne.__class__, ne))
except Exception as e: #NameError is the only one that should get here
print("Exception- {0}: {1}".format(e.__class__, e))
The language accepts the not in the except clause, but does nothing with it:
>>> Exception- <type 'exceptions.NameError'>: name 'asdjaslk' is not defined
Is it possible to do this or should I reraise them?
You'll have to re-raise. An except statement can only whitelist, not blacklist.
try:
asdjaslk
except Exception as ne:
if isinstance(ne, NameError):
raise
The not NameError expression returns False, so you are essentially trying to catch:
except False:
but no exception will ever match a boolean instance.
The syntax allows for any valid Python expression, and the thrown exception is matched against the outcome of that expression. except SomeException if debug else SomeOtherException: is perfectly valid, for example.
You can can try this:
try:
# your code raising exceptions
except NameError:
# catch the exception you don't want to catch
# but immediately raise it again:
print("re-raising NameError- {0}: {1}".format(ne.__class__, ne))
raise
except Exception as e:
# handle all other exceptions here
print("catching Exception- {0}: {1}".format(e.__class__, e))
pass
I'm trying to do a nested try/catch block in Python to print some extra debugging information:
try:
assert( False )
except:
print "some debugging information"
try:
another_function()
except:
print "that didn't work either"
else:
print "ooh, that worked!"
raise
I'd like to always re-raise the first error, but this code appears to raise the second error (the one caught with "that didn't work either"). Is there a way to re-raise the first exception?
raise, with no arguments, raises the last exception. To get the behavior you want, put the error in a variable so that you can raise with that exception instead:
try:
assert( False )
# Right here
except Exception as e:
print "some debugging information"
try:
another_function()
except:
print "that didn't work either"
else:
print "ooh, that worked!"
raise e
Note however that you should capture for a more specific exception rather than just Exception.
You should capture the first Exception in a variable.
try:
assert(False)
except Exception as e:
print "some debugging information"
try:
another_function()
except:
print "that didn't work either"
else:
print "ooh, that worked!"
raise e
raise by default will raise the last Exception.
raise raises the last exception caught unless you specify otherwise. If you want to reraise an early exception, you have to bind it to a name for later reference.
In Python 2.x:
try:
assert False
except Exception, e:
...
raise e
In Python 3.x:
try:
assert False
except Exception as e:
...
raise e
Unless you are writing general purpose code, you want to catch only the exceptions you are prepared to deal with... so in the above example you would write:
except AssertionError ... :
How to handle all but one exception?
try:
something
except <any Exception except for a NoChildException>:
# handling
Something like this, except without destroying the original traceback:
try:
something
except NoChildException:
raise NoChildException
except Exception:
# handling
The answer is to simply do a bare raise:
try:
...
except NoChildException:
# optionally, do some stuff here and then ...
raise
except Exception:
# handling
This will re-raise the last thrown exception, with original stack trace intact (even if it's been handled!).
New to Python ... but is not this a viable answer?
I use it and apparently works.... and is linear.
try:
something
except NoChildException:
assert True
except Exception:
# handling
E.g., I use this to get rid of (in certain situation useless) return exception FileExistsError from os.mkdir.
That is my code is:
try:
os.mkdir(dbFileDir, mode=0o700)
except FileExistsError:
assert True
and I simply accept as an abort to execution the fact that the dir is not somehow accessible.
I'd offer this as an improvement on the accepted answer.
try:
dosomestuff()
except MySpecialException:
ttype, value, traceback = sys.exc_info()
raise ttype, value, traceback
except Exception as e:
mse = convert_to_myspecialexception_with_local_context(e, context)
raise mse
This approach improves on the accepted answer by maintaining the original stacktrace when MySpecialException is caught, so when your top-level exception handler logs the exception you'll get a traceback that points to where the original exception was thrown.
You can do type checking on exceptions! Simply write
try:
...
except Exception as e:
if type(e) == NoChildException:
raise
It still includes the original stack trace.
I found a context in which catching all errors but one is not a bad thing, namely unit testing.
If I have a method:
def my_method():
try:
something()
except IOError, e:
handle_it()
Then it could plausibly have a unit test that looks like:
def test_my_method():
try:
my_module.my_method()
except IOError, e:
print "shouldn't see this error message"
assert False
except Exception, e:
print "some other error message"
assert False
assert True
Because you have now detected that my_method just threw an unexpected exception.