How to catch all old-style class exceptions in python? - python

In a code where there are different old-style classes like this one:
class customException: pass
and exceptions are raised this way:
raise customException()
Is there a type to catch all those old-style class exceptions? like this:
try:
...
except EXCEPTION_TYPE as e:
#do something with e
Or at least is there a way to catch everything (old- and new-style) and get the exception object in a variable?
try:
...
except:
#this catches everything but there is no exception variable

The only solution I can think of is using sys.exc_info
import sys
try:
raise customException()
except:
e = sys.exc_info()[1]
# handle exception "e" here...

Related

How does it help to subclass an exception?

Instead of calling the exception directly, I have seen it is subclassed with nothing in it or a pass statement. How does it help Python internally to subclass a base class, in this manner? Does it change namespace or signature? How?
class ACustomException(Exception):
pass
class BCustomException(Exception):
pass
Raising Exception is like telling the doctor "Something's wrong" and then refusing to answer any questions. Compare:
try:
with open("foo.json", "rt") as r:
new_count = json.load(r)["count"] + 1
except Exception:
# Is the file missing?
# Is the file there, but not readable?
# Is the file readable, but does not contain valid JSON?
# Is the file format okay, but the data's not a dict with `count`?
# Is the entry `count` there, but is not a number?
print("Something's wrong")
# I don't care. You figure it out.
and
try:
with open("data.json", "rt") as r:
new_count = json.load(r)["count"] + 1
except FileNotFoundError:
print("File is missing.")
except PermissionError:
print("File not readable.")
except json.decoder.JSONDecoderError:
print("File is not valid JSON.")
except KeyError:
print("Cannot find count.")
except TypeError:
print("Count is not a number.")
If you are making a library, you can use the predefined exception classes where appropriate — but sometimes you need to communicate errors that Python creators never thought about, or you need to make a finer distinction than the existing exceptions do. This is when you'd create a custom exception.
For example, Django will define django.contrib.auth.models.User.DoesNotExist exception to communicate that the code tried to look for a User in the database, but no User matching the given criteria could be found. Being able to catch django.contrib.auth.models.User.DoesNotExist is like being a doctor, and getting a patient that not only tells you what hurts, but brings X-rays and a printed family history with them.
When you're handling exceptions with try-except, you're catching them by name, so having specific names helps you handle them.
For example, if a function raises Exception for any error, the catching logic gets complicated:
def foobar():
if FOO:
raise Exception('FOO happened')
elif BAR:
raise Exception('BAR happened')
try:
foobar()
except Exception as e:
if e.args == ('FOO happened',):
print('Handling FOO')
elif e.args == ('BAR happened',):
print('Handling BAR')
else:
raise
On the other hand if you have subclassed exceptions, the catching logic is simple:
class FooError(Exception):
pass
class BarError(Exception):
pass
def function():
if FOO:
raise FooError('FOO happened')
elif BAR:
raise BarError('BAR happened')
try:
function()
except FooError:
print('Handling FOO')
except BarError:
print('Handling BAR')
It helps with determining 'what' the traceback issue is referring to in case of maybe a web service that you maybe running, so it's not low-level or the generic errors you normally get back rather the exception class that would be used.
To be more specific with an example:
val = int(input('Enter a number:'))
try:
val *= val
except ValueError as e:
raise e
print(val)
### ValueError will be raised if user inputs something other than a number
### this raise e will return the actual error message saying
### ValueError: invalid literal for int() with base 10: 'ok'
In your case, you could still raise your exception keeping ValueError as the except to be handled for, like this:
val = int(input('Enter a number:'))
try:
val *= val
except ValueError as e:
raise ACustomException('some debug statement referring to the cause of the error')
print(val)
### now this will raise your exception class besides the ValueError exception, with a debug statement if you choose to have one in it.

Exceptions in Python(multiple try blocks)

I am new to python and I have been wondering if you can do something like this in python.
try:
something():
if it throws an exception then try this:
something1():
if it throws an exception again:
print(exception)
Of course you can.
try:
something()
except Exception as exp:
try:
something1()
except Exception as exp2:
print(exp, exp2)
raise exp # in case you want to raise the original exception

Catching all Custom Exceptions Python

I have a number of custom exceptions created for my Django project. like so
errors.py
# General Exceptions
class VersionError(Exception):
pass
class ParseError(Exception):
pass
class ConfigError(Exception):
pass
class InstallError(Exception):
pass
However I want to print the output from my custom exceptions but not the general. But do not want to list them all out, i.e
try:
do something wrong
except <custom errors>, exc:
print exc
except:
print "Gen
Canonical way would be to create common superclass for all your exceptions.
# General Exceptions
class MyAppError(Exception):
pass
class VersionError(MyAppError):
pass
class ParseError(MyAppError):
pass
class ConfigError(MyAppError):
pass
class InstallError(MyAppError):
pass
With this inheritance three you may simply catch all exceptions of type MyAppError.
try:
do_something()
except MyAppError as e:
print e
You could make a tuple of the exceptions:
my_exceptions = (VersionError,
ParseError,
ConfigError,
InstallError)
Usage:
except my_exceptions as exception:
print exception
e.g:
>>> my_exceptions = (LookupError, ValueError, TypeError)
>>> try:
... int('a')
... except my_exceptions as exception:
... print type(exception)
... print exception
<type 'exceptions.ValueError'>
invalid literal for int() with base 10: 'a'
You should define a custom marker base class for your custom exceptions:
# General Exceptions
class MyException(Exception):
"""Just a marker base class"""
class VersionError(MyException):
pass
class ParseError(MyException):
pass
class ConfigError(MyException):
pass
class InstallError(MyException):
pass
With that modification, you can then easily say:
try:
do something wrong
except MyException as exc:
print exc
except:
print "Some other generic exception was raised"
(BTW, you should use the recommended except Exception as ex syntax instead of the except Exception, ex, see this question for details)
You should make a common base class for all your custom exceptions, and catch that.
Create a custom base exception and derive all the other custom exceptions form this base execption:
class CustomBaseException(Exception):
pass
# General Exceptions
class VersionError(CustomBaseException):
pass
class ParseError(CustomBaseException):
pass
class ConfigError(CustomBaseException):
pass
class InstallError(CustomBaseException):
pass
Then you can do
try:
do something wrong
except CustomBaseExecption, exc:
print exc
except:
print "Gen

except block does not catch the exception in python

my code is like below
class Something(models.Model)
def exception(self)
try:
Something.objects.all()
except Exception():
raise Exception()
called this method from testcases ,its working but i need to raise exception ,it does not catch the exception
and here is my test case
def test_exception(self):
instance = Something()
instance.exception()
its working fine but i need to raise exception from except block
This line:
except Exception():
should be:
except Exception:
def exception(self)
try:
Something.objects.all()
except Exception, err:
#print err.message (if you want)
raise err
This will catch the error and print the exact msg if required.
Why catch the Exception just to re-raise it?
If you are not doing anything in the except suite except re-raising the exception, then simply do not catch the exception in the first place:
#staticmethod
def exception():
Something.objects.all()
If you are doing something nontrivial inside the except suite, then:
def exception(self):
try:
Something.objects.all()
except Exception:
# do something (with self?)
raise
Then, to test that the exception method raises an Exception:
def test_exception(self):
instance = Something()
self.assertRaises(Exception, instance.exception)
This depends on Something.objects.all() raising Exception.
PS. If exception does not depend on self, then it is best to remove it from the argument list and make exception a staticmethod.
PPS. Exception is a very broad base exception class. A more specific exception would be more helpful for debugging, and allow other code to catch this specific exception instead of forcing it to handle any possible Exception.

Python logging exception

I'm currently writing a wrapper class. I want to be able to log exceptions properly but allow calling methods to be aware of exceptions which occur. My class looks like this:
import logging
log = logging.getLogger('module')
class MyAPIWrapper(library.APIClass):
def __init__(self):
self.log = logging.getLogger('module.myapiwrapper')
def my_wrapper_method(self):
try:
response = self.call_api_method()
return response.someData
except APIException, e:
self.log.exception('Oh noes!')
raise e #Throw exception again so calling code knows it happened
I'm a bit dubious about catching and exception just to log it and then re-raising it so the calling code can do something about it. What's the proper pattern here?
There is nothing wrong with catching to log. However, I'd recommend:
try:
response = self.call_api_method()
except APIException, e: # or 'as e' depending on your Python version
self.log.exception('Oh noes!')
raise #Throw exception again so calling code knows it happened
else:
return response.someData
By just doing a bare raise you preserve the full traceback info. It's also more explicit to put code that will only happen if you don't have an exception in the else clause, and it's clearer what line you're catching an exception from.
It would also be fine for the calling class to do the logging if it's handling the error anyway, but that may not be convenient for your app.
Edit: The documentation for try ... except ... else ... finally is under compound statements.
That method is correct, although instead of raise e you should just use raise, which will automatically re-raise the last exception. This is also one of the rare cases where using a blanket except is considered acceptable.
Here is an example very similar to what you are doing from the Python docs on Handling Exceptions:
The last except clause may omit the exception name(s), to serve as a wildcard. Use this with extreme caution, since it is easy to mask a real programming error in this way! It can also be used to print an error message and then re-raise the exception (allowing a caller to handle the exception as well):
import sys
try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except IOError as (errno, strerror):
print "I/O error({0}): {1}".format(errno, strerror)
except ValueError:
print "Could not convert data to an integer."
except:
print "Unexpected error:", sys.exc_info()[0]
raise
You can just extend the standard Exception class and add the logger into there.
Like this:
class LoggedException(Exception):
""" An exception that also logs the msg to the given logger. """
def __init__(self, logger: logging.Logger, msg: str):
logger.error(msg)
super().__init__(msg)

Categories