I am not sure if this is a python question or a Tornado question. But I am struggling to figure out how I can handle an exception if something fails.
Here is the snippet of code:
class iQHandler(myBaseHandler):
#tornado.gen.coroutine
def _initialize(self):
param1 = self.get_argument('media', None)
if not param1:
raise tornado.web.HTTPError(404)
# default the Output parameter to JSON format.
outputFormat = self.get_argument('output', 'json', False)
try:
res = yield self._findfiles(param1)
except Exception, e:
# What do I do here?
print ("Error in _initialize() routine --> ", e)
# The variable, res, doesn't have any value if there is an exception thrown.
raise tornado.gen.Return(res)
#tornado.web.asynchronous
#tornado.gen.coroutine
def get(self):
response = yield self._initialize()
self.clear()
self.finish(response)
How will I go about either raising an exception and returning a value back to the previous routine? Thanks.
This is a python question. The try except block is fine. You can reraise the same exception by saying raise in the except block without anything after raise. That is, replace
raise tornado.gen.Return(res)
by
raise
Note the indent to keep the raise in the except block.
Related
i have custom exception for inserting data:
class ErrorOnInsert(BaseException):
"""Exception raised for errors in insert data to db
Attributes:
resource -- resource name
message -- explanation of the error
"""
def __init__(self, resource: str):
self.message = 'Failed to insert data for {}!'.format(resource)
super().__init__(self.message)
exception is used in this insert function to mongo:
def _add(self, data: RunnerRating):
try:
dict_data = data.as_dict()
self.collection[self.document_name].insert_one(
dict_data)
self.list_data.add(data)
except ErrorOnInsert(self.document_name) as e:
raise e
and i try to test the exception with self.repo._add(None) but it shows error something like this:
FAILED tests/integration/test_repo.py::RatingRepoTest::test_add -
TypeError: catching classes that do not inherit from BaseException is
not allowed
Your syntax looks like it's a catch with a pattern match (which isn't a thing in Python).
Are you maybe looking for
def _add(self, data: RunnerRating):
try:
dict_data = data.as_dict()
self.collection[self.document_name].insert_one(dict_data)
self.list_data.add(data)
except Exception as e:
raise ErrorOnInsert(self.document_name) from e
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.
If I have the function,
def parse_datetime(s, **kwargs):
""" Converts a time-string into a valid
:py:class:`~datetime.datetime.DateTime` object.
Args:
s (str): string to be formatted.
``**kwargs`` is passed directly to :func:`.dateutil_parser`.
Returns:
:py:class:`~datetime.datetime.DateTime`
"""
if not s:
return None
try:
ret = dateutil_parser(s, **kwargs)
except (OverflowError, TypeError, ValueError) as e:
logger.exception(e, exc_info=True)
raise SyncthingError(*e.args)
return ret
What's the most correct way to raise the caught exception as the common library exception? (SyncthingError(Exception) ) The way it's written right now does not work correctly.
In Python 3 the exceptions can be chained,
raise SyncthingError("parsing error") from e
will produce a stack trace with details of the original exception.
There are examples in the raise statement docs.
You should be able to raise it as long as constructer of the common library exception takes Error or Exception. For example:
Class LibraryException(Exception)...
Class LibraryException(Error)...
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.
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)