I am trying to raise an exception inside the exception, without getting an error message of the outer exception and the traceback and print the hey only. However, I am a quite stuck here if I put a string instead of k or m. Any ideas?
The output, which I would need without the traceback
def division(k, m):
try:
k / m
except TypeError:
raise ValueError ('hey') from None
return k / m
I'm not exactly sure what you are trying to achieve here, but why don't you just print the string "hey" when the TypeError is raised? Like this:
def division(k, m):
try:
k / m
except TypeError:
print("hey")
return None
return k / m
If you need to raise the ValueError for any reason, then you can catch the ValueError where you call the method, I guess:
def division(k, m):
try:
k / m
except TypeError:
raise ValueError
return k / m
try:
division("not_an_int", "could_be_an_int")
except ValueError:
print("hey")
From what I understand, You want a custom exception with a custom message format.
class CustomException(Exception):
def __init__(self, message):
self.message = message # You can also set it by default so you don't need to input any message
super().__init__(self.message)
def __eq__(self, other):
return self.message == other.message
def __str__(self):
return f'{self.message}' # In your case, just to display message.
# return f'Error message: {self.message}'
def division(k, m):
try:
k / m
except TypeError:
raise CustomException(message="hey")
return k / m
try:
division("not_an_int", "could_be_an_int")
except ValueError as e:
print(e)
It is not entirely clear what you are trying to achieve here. You don't get the error message because you raise the exception but because you don't catch it again. If you don't want the error message, you need to catch the exception. Then, if you just want to print the message 'hey' you can get it from the exception args.
try:
division('a', 2)
except ValueError as e:
print(e.args[0])
The raise ... from None already got rid of the first exception, so you are only seeing the ValueError you raise in the except block in division, but if an exception makes it all the way out to the command line, you have to be informed somehow, and Python will do so by printing the error message.
Now, you can change the default behaviour for uncaught exceptions if you want to. This, for example, will print the args[0] for all exceptions you do not explicitly catch.
import sys
def handle_exception(exc_type, exc_value, exc_traceback):
print('handler:', exc_value.args[0])
sys.excepthook = handle_exception
The sys.excepthook is a function Python will call for an uncaught exception. So if you do
try:
division('a', 2)
except ValueError as e:
print('caught:', e)
division('a', 2) # not caught
the first division exception is caught, and the handler isn't invoked, and the second isn't caught and the handler is used (and will just print the message 'hey').
It is not really a great idea to change the way all uncaught exceptions are handled, though. You probably want to handle only your own and use the default behaviour for anything else.
But, as I said, it is not entirely clear to me what you are trying to achieve, so all of the above might be entirely unrelated to the question.
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
Consider the following code:
def f(x):
if x < 10:
return Exception("error")
else:
raise Exception("error2")
if __name__ == "__main__":
try:
f(5) # f(20)
except Exception:
print str(Exception)
Is there any difference?
When should I use return Exception and When should I use raise?
raise and return are two inherently different keywords.
raise, commonly known as throw in other languages, produces an error in the current level of the call-stack. You can catch a raised error by covering the area where the error might be raised in a try and handling that error in an except.
try:
if something_bad:
raise generate_exception()
except CertainException, e:
do_something_to_handle_exception(e)
return on the other hand, returns a value to where the function was called from, so returning an exception usually is not the functionality you are looking for in a situation like this, since the exception itself is not the thing triggering the except it is instead the raiseing of the exception that triggers it.
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()
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
I'm adding logging to some python code that deals with exceptions, in the example below what's the correct syntax for wanting to log exception details (e.g. via logger.exception()) when a TypeError or AttributeError occurs?
try:
...
except (TypeError, AttributeError):
# want to do a logger.exception(x) here but not sure what to use for x
...
raise CustomError("Unable to parse column status)
exception(...) is just a convenience method which takes a message just like the other methods:
def exception(self, msg, *args):
"""
Convenience method for logging an ERROR with exception information.
"""
self.error(msg, exc_info=1, *args)
So you would just use it like
logger.exception("Some error message")
and the logging handler will automatically add the exception information from the current exception. Only use this in an exception handler (i.e. in a except: block)!
If you want the exception details, you need to bind the exception itself to a local variable, like this:
except (TypeError, AttributeError), e:
# e is the Exception object
logger.exception(e)
If you need to do different things based on the type of the exception, then you can catch them separately:
except TypeError, e:
logger.exception('There was a Type Error; details are %s' % e)
# Do something, or raise another exception
except AttributeError, e:
logger.exception('There was an Attribute Error; details are %s' % e)
# Do something, or raise another exception
And if you need more information about the context of the exception itself, look into the sys.exc_info() function; it can get you the traceback, and the details about exactly where the exception occurred.