I have some function:
def reverse_number(num):
try:
return int(num)
except ValueError:
return "Please provide number"
and test for this:
assert_raises(ValueError, reverse.reverse_number, "error")
But when I call nosetests I got this error:
AssertionError: ValueError not raised
What am I doing wrong?
The function reverse_number catches the exception, preveting the exception to be raised; cause the assertion failure because assert_raises call expects the function call raises the ValueError exception.
Simply not catching the exception, you can get what you want:
def reverse_number(num):
return int(num)
Or, you can catch the exception, do something, and re-raise the exception using raise statement:
def reverse_number(num):
try:
return int(num)
except ValueError:
# do something
raise # <--- re-raise the exception
Related
I expect a python function I use to raise a KeyError, in case the user of my script entered a wrong value.
When this happens, I want to raise a ValueError, not a KeyError. I tried to catch the KeyError, then raise a ValueError instead. I then get both.
For example:
def func(my_dict):
return my_dict["my_key"]
a = {}
try:
func(a)
except KeyError as e:
raise ValueError("Replaced exception")
results in this:
$ python3 except.py
Traceback (most recent call last):
File "except.py", line 7, in <module>
func(a)
File "except.py", line 2, in func
return my_dict["my_key"]
KeyError: 'my_key'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "except.py", line 9, in <module>
raise ValueError("Replaced exception")
ValueError: Replaced exception
I don't care about the KeyError itself, I just want to tell the user about the ValueError.
How can I catch the KeyError, but discard it? Is it bad practice? How should I organize this instead?
One way, described here, is to raise ... from None
def func(my_dict):
return my_dict["my_key"]
a = {}
try:
func(a)
except KeyError as e:
raise ValueError("Replaced exception") from None
But I'm still not sure if this is a good idea or not.
What you stumbled upon is the difference between an exceptions cause and it's context. There are three slightly different things you can do, and each have different semantics:
Version 1:
try:
raise KeyError()
except KeyError as ex:
raise ValueError()
This will show both trackbacks separated by the line
During handling of the above exception, another exception occurred:
This is saying: There was one exception, and in the catch block there was another (unrelated, usually unexpected) exception. This is not what you want here.
Version 2:
try:
raise KeyError()
except KeyError as ex:
raise ValueError() from None
This will just show the traceback for the ValueError. This might be what you want, if you are really sure you never ever have to debug the KeyError. Otherwise, read on.
Version 3
try:
raise KeyError()
except KeyError as ex:
raise ValueError() from ex
Again, this will show both tracebacks, this time separated by the line
The above exception was the direct cause of the following exception:
Notice the difference from Version 1? Semantically this says: On this level of abstraction this is a ValueError. But in case you need to debug it, here's the traceback of the original KeyError, too. Pretty neat, don't you think?
You don't have a try/except block to manage the ValueError. So, what you're seeing is a stack trace that's telling you where the ValueError originated.
Consider this:
def func(my_dict):
return my_dict["my_key"]
a = {}
try:
try:
func(a)
except KeyError as e:
raise ValueError("Replaced exception")
except ValueError as e:
print(e)
Output:
Replaced exception
i.e.,
No stack trace because you've caught the ValueError
Python 3 allows raising exceptions from other exceptions e.g.:
try:
raise CustomException()
except CustomException as e:
try:
raise TypeError() from e
except TypeError as e:
print(type(e.__cause__))
The CustomException instance is stored in the exception object's __cause__ attribute.
The code above should print CustomException.
Is there a way to catch the original exception instead of the newly raised one?
try:
raise CustomException()
except CustomException as e:
try:
raise TypeError() from e
except CustomException as e:
print(type(e)) # should reach here
Overriding __subclasscheck__ does not work since I don't have access to the instance and I it is impossible to specify that CustomException is a subclass of all classes or of the cause class.
Is there a way to trick Python into thinking that the exception we're catching is of the type of __cause__?
If you have control over the exception that is raised you can perhaps make it a subclass of the raised exception:
try:
raise TypeError()
except TypeError as e:
try:
class CustomException(TypeError.__class__):
pass
raise CustomException() from e
except TypeError as e:
print(type(e)) # Reaches here
That said, the mechanism of catch-and-reraise is meant to hide what the original exception was so that later code doesn't depend on implementation details.
Simple solution: catch all exceptions and filter required:
try:
raise ZeroDivisionError()
except ZeroDivisionError as e:
try:
raise TypeError() from e
except Exception as ex:
if type(ex.__cause__) is ZeroDivisionError:
print('ZeroDivisionError')
else:
raise # re-raise exception if it has different __cause__
In my example I have a custom exception class MyCustomException and in main I divide an integer a by zero which raises a ZeroDivisionError exception. With the except block I catch ZeroDivisionError and then raise MyCustomException from err; this creates a chained exception, my own, plus the one in err.
Now how can I catch chained exceptions or how do chained exceptions work? Python doen't let me to catch MyCustomException in my code with except block.
class MyCustomException(Exception):
pass
a=10
b=0
reuslt=None
try:
result=a/b
except ZeroDivisionError as err:
print("ZeroDivisionError -- ",err)
raise MyCustomException from err
except MyCustomException as e:
print("MyException",e) # unable to catch MyCustomException
The output I get when I execute it:
ZeroDivisionError -- division by zero
Traceback (most recent call last):
File "python", line 13, in <module>
MyCustomException
Using raise in the except clause won't search for exception handlers in the same try block (it did not occur in that try block).
It will search for handlers one level up , that is, an outer try block. If that isn't found it'll interrupt execution as it normally does (resulting in the exception being displayed).
In short, you need an enclosing try in the outer level with the appropriate except MyCustomException in order to catch your custom exception:
try:
try:
result=a/b
except ZeroDivisionError as err:
print("ZeroDivisionError -- ",err)
raise MyCustomException from err
except MyCustomException as e:
print("Caught MyException", e)
Which, when executed, now prints out:
ZeroDivisionError -- division by zero
Caught MyException
I'm wondering a user defined exception I've raised in my python program from within a class isn't being handled by the correct exception handler within my main(). Say I have a class:
class Pdbalog:
# Constructor
def __init__(self, logtype):
if logtype == 1 or logtype == 2:
# These are valid
self.logtypeV = logtype
...<continue processing>
else:
# Invalid
raise Exception("Invalid Logtype")
My main looks like:
from pdbalog import *
def main():
try:
mylog = Pdbalog(10)
...<other code here>
except "Invalid Logtype":
print('Exiting...')
except:
print('Unhandled exception')
raise
I would expect the when main is run that the line where I instantiate the Pdbalog object would raise an exception (Exception("Invalid Logtype")) and the exception handler in main (except "Invalid Logtype") would print the output string "Exiting...". However, it does not. It is being handled by the unhandled exception handler. What ends up happening is the string "Unhandled exception" is being output. Why isn't the
except "Invalid Logtype":
handling the exception?
I am using an old version of python (2.4).
Exception("Invalid Logtype") is still just an Exception, just now with an error message. "Invalid Logtype" isn't an error, just a str, so you can't catch it.
Try:
class InvalidLogtype(Exception): pass
try:
raise InvalidLogType
except InvalidLogType:
pass
Note that you can catch based on error messages by doing
except Exception, e:
if e.args == ("Invalid Logtype",):
...
else:
raise
Try this instead:
class InvalidLogType(Exception):
pass
then
raise InvalidLogType()
then
except InvalidLogType:
etc
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.