I am facing a problem while catching the exception in my unitest code.
Following is my code
def get_param(param)
if param is None:
raise ValueError('param is not set')
def test_param():
with pytest.raises(ValueError) as e:
get_param()
The problem is that when function does not raise exception, test_param() gets fail with the following error.
Failed: DID NOT RAISE <class 'ValueError'>
It works as expected when get_param(param) function throws exception.
I have faced same problem. This solutions works for me.
try:
with pytest.raises(ValidationError) as excinfo:
validate_bank_account_number(value=value)
assert excinfo.value.args[0] == 'your_error_message_returned_from_validation_error'
except:
assert True
It's not a problem, python.raises works as expected. By using it you're asserting a certain exception.
If you really don't want to get the exception, you can use try-except to catch and suppress it like this:
from _pytest.outcomes import Failed
def test_param():
try:
with pytest.raises(ValueError):
get_param()
except Failed as exc:
# suppress
pass
# or
# do something else with the exception
print(exc)
# or
raise SomeOtherException
Related
I need to return update/insert result, from the database class, back to the calling class to differentiate
between success and error.
An update/insert returns <type long'> while a database error returns
<class '_mysql_exceptions.DataError'>.
Since I am not sure about the return type during a success that it would always be a long type, I am checking for type class.
And, I couldn't do it. I tried these:
try:
x = cursor.execute(q, d)
conn.commit()
return x #Return this to the calling class
except MySQLdb.Error, e:
return e #Return this to the calling class
if isinstance(e, class): #Doesn't work
if issubclass(e, _mysql_exceptions): #Doesn't work
How do I check the type of e here?
If I am doing it all wrong, please suggest something nice, thanks.
The issue is that isinstance(obj, class) is not valid syntax, and _mysql_exceptions is a module, not an exception type, which raises a TypeError. To explicitly check an exception type, you can catch each individually:
from _mysql.exceptions import DataError, SomeOtherError, ...
from requests import HTTPError # as an example of a different error
try:
x = cursor.execute(q, d)
conn.commit()
except DataError as e:
# do something
except SomeOtherError as e:
# do something else
except HTTPError as e:
# your connection is broken
# maybe raise from e?
You need to catch that explicit error type, then you don't need to do if isinstance. Start with no exception handling at all, this will lead you to the exceptions that you do need to handle, and anything else should be considered unexpected and should cause the application to either crash or propagate some helpful error message to let you know something bad happened:
try:
some_function()
except ValueError as e:
# this is expected, and is handled accordingly
handle_expected_error()
# This is optional, normally a bare exception block is considered bad practice,
# but can allow your application to continue functioning while raising some
# helpful error so this isn't suppressed
except Exception as e:
# this is not expected, I'm going to propagate this error
# up to be obvious what happened
handle_unexpected_error()
#or
raise from e
Edit: What if I want a calling class to handle the exception?
Reasonable, and I would lean on catching the exception. Instead of handling the exception, I would allow the function to just raise the exception and handle it in the calling class. As a really simple example:
class MyClass:
def __init__(self, conn, cursor):
self.conn = conn
self.cursor = cursor
def some_function(self):
# This raises an error, note I'm not handling it here
x = self.cursor.execute()
self.conn.commit()
return x
def main_function(self):
try:
x = self.some_function()
except DataError as e:
handle_exception()
# unexpected, handle this here
except Exception as e:
raise from e
# or do something else
I have:
MY_PATH_DIR = 'path/to/my/json/file.json'
try:
with open(MY_PATH_DIR, 'r') as f:
MY_PATH_DIR = json.load(f)
except IOError, RuntimeError, ValueError:
pass
except PermissionDenied:
pass
And I want to catch all possible errors. With
IOError - I am catching errors when the file doesn't exist or has a
syntax error (non valid JSON).
RuntimeError - couldn't test it but I think that makes sense from the
documentation in case of an unexpected error
ValueError - I got from here in case nothing got returned
PermissionDenied - is a specific Django error
Are there any other Exceptions that would make sense? I'm not sure if OSError makes sense here. I think that would be raised earlier, right?
The purpose of capturing exceptions is to control the program's behavior when something bad happened, but in an expected way. If you are not even sure what would cause that exception happen, capturing it would only swallow the underlying programming errors you might have.
I wouldn't add as many kinds of exception as possible to that single block of code, you should only add what you care about. To take it to extreme, each line of code would yield certain exceptions but for obvious reason you couldn't do try except for all of them.
Edit:
For the sake of correctness, since you mentioned I don't want my code to break in any case, you could simply do:
try:
# json.load
except Exception as e:
print "Let's just ignore all exceptions, like this one: %s" % str(e)
This is would give you what exception happens as output.
import random
import sys
def main():
"""Demonstrate the handling of various kinds of exceptions."""
# This is like what you are doing in your code.
exceptions = IOError, RuntimeError, ValueError
try:
raise random.choice(exceptions)()
except exceptions as error:
print('Currently handling:', repr(error))
# The following is not much different from Shang Wang's answer.
try:
raise random.choice(exceptions)()
except Exception as error:
print('Currently handling:', repr(error))
# However, the following code will sometimes not handle the exception.
exceptions += SystemExit, KeyboardInterrupt, GeneratorExit
try:
raise random.choice(exceptions)()
except Exception as error:
print('Currently handling:', repr(error))
# The code can be slightly altered to take the new errors into account.
try:
raise random.choice(exceptions)()
except BaseException as error:
print('Currently handling:', repr(error))
# This does not take into account classes not in the exception hierarchy.
class Death:
pass
try:
raise Death()
except BaseException as error:
print('Currently handling:', repr(error))
# If your version of Python does not consider raising an exception from an
# instance of a class not derived from the BaseException class, the way to
# get around this problem would be with the following code instead.
try:
raise Death()
except:
error = sys.exc_info()[1]
print('Currently handling:', repr(error))
if __name__ == '__main__':
main()
Lets say I have this:
try:
result = call_external_service()
if not result == expected:
raise MyException()
except MyException as ex:
# bubble up
raise ex
except Exception:
# unexpected exceptions from calling external service
do_some_logging()
Due to my limited python knowledge, I cannot think of an elegant way to bubble up the MyException exception, I was hoping I can do something like:
try:
result = call_external_service()
if not result == expected:
raise MyException()
except Exception, exclude(MyException):
# unexpected exceptions from calling external service
do_some_logging()
Your problem seems to be that you are wrapping too much code in your try block. What about this?:
try:
result = call_external_service()
except Exception:
# unexpected exceptions from calling external service
do_some_logging()
if result != expected:
raise MyException()
eg:
try:
myfruits = FruitFunction() #Raises some exception (unknown)
assert "orange" in myfruits #Raises AssertionError (known)
except:
# I don't know how to distinguish these two errors :(
I need to filter out one particular kind of exception (which is known) from all others that are unknown. I also need assertion to continue the same exception handling,
try:
myfruits = FruitFunction() #Raises some exception (unknown)
assert "orange" in myfruits #Raises AssertionError (known)
except AssertionError:
# Handle Assertion Errors here
# But I want the except below to happen too!
except:
# Handle everything here
I will add one real example to convey the idea more concisely:
try:
# This causes all sorts of errors
myurl = urllib.urlopen(parametes)
# But if everything went well
assert myurl.status == 202
# proceed normal stuff
except:
# print "An error occured" if any error occured
# but if it was an assertion error,
# add "it was something serious too!"
try:
try:
myfruits = FruitFunction() #Raises some exception (unknown)
assert "orange" in myfruits #Raises AssertionError (known)
except AssertionError:
# handle assertion
raise
except Exception:
# handle everything
I'm assuming you can't separate the two statements that throw the different exceptions (because they're off together in another function, for example). If you can then the following is more precise and straightforward:
try:
myfruits = FruitFunction() #Raises some exception (unknown)
try:
assert "orange" in myfruits #Raises AssertionError (known)
except AssertionError:
# handle assertion
raise
except Exception:
# handle everything
It's more precise because if the unknown exception raised by FruitFunction() happens to be AssertionError then it won't get caught in the inner try. Without separating the statements, there's no (sensible) way to distinguish two exceptions of the same type thrown from the two different places. So with the first code you'd better hope that FruitFunction() either doesn't raise AssertionError, or that if it does then it can be handled the same way as the other one.
try:
# Do something
myurl = urllib.urlopen(parametes)
assert myurl.status == 202
except Exception as e:
# Handle Exception
print('An error occured')
if isinstance(e, AssertionError):
# Handle AssertionError
print('it was something serious too!')
else:
# proceed normal stuff
In the case that it's both raised an unknown exception and an AssertionError, and you need to handle both, you should use two separate try statements.
try:
raise IndexError()
assert 'orange' in myfruits
except AssertionError:
print 'AssertionError'
except:
print 'another error'
The above will only catch the first error, while
try:
raise IndexError()
except:
print 'another error'
try:
assert 'orange' in myfruits
except AssertionError:
print 'AssertionError'
Will catch both errors.
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.