django - catch multiple exceptions - python

I have this view function:
def forum(request):
qs = Forum.objects.all()
try:
f = Forum.objects.filter().order_by('-id')[0] <------------problem
return render_to_response("forum.html",{'qs':qs,'f':f},context_instance=RequestContext(request))
except Forum.DoesNotExist or IndexError:
return render_to_response("forum.html",{'qs':qs},context_instance=RequestContext(request))
but it is still giving following error for the problem line above:
IndexError: list index out of range
is my code fine? can i catch multiple exceptions in this way?

When you have this in your code:
except Forum.DoesNotExist or IndexError:
It's actually evaluated as this:
except (Forum.DoesNotExist or IndexError):
where the bit in parentheses is an evaluated expression. Since or returns the first of its arguments if it's truthy (which a class is), that's actually equivalent to merely:
except Forum.DoesNotExist:
If you want to actually catch multiple different types of exceptions, you'd instead use a tuple:
except (Forum.DoesNotExist, IndexError):

You can catch multiple exceptions in this manner
try:
...
except (Forum.DoesNotExist, IndexError) as e:
...

If you want to log/handle each exception, then you can do it like this.
from django.core.exceptions import ObjectDoesNotExist
try:
your code here
except KeyError:
logger.error('You have key error')
except ObjectDoesNotExist:
logger.error('Object does not exist error')

Related

Catch exception in loop head but not in loop body

What's the best way to catch exceptions which occur in the *loop header instead of the whole loop or body.
Take the following example
for value in complex_generator(): # throws exceptions I might want to catch
... # do work here - but don't catch any exception
What I don't consider helpful is wrapping the whole loop in a try and except block like so:
try:
for value in complex_generator(): # throws exceptions I might want to catch
... # exceptions raised here will also be caught :(
except Exception:
... # handle exception here
Inspired from golang one might encapsulate the try-except-block and always return two elements:
def wrapper(iterable):
try:
for value in iterable:
yield value, None
except Exception as e:
yield None, e
for value, err in wrapper(complex_generator()):
if err != None:
... # handle error
else:
... # do work but don't catch any exception here
This however doesn't feel pythonic and a type checker would also require a additional check. Any ideas?
There are two levels of errors: Those that the generator throws, and those that your worker code throws. I would use a nested try:
try:
for value in complex_generator():
try:
# do work here
except ValueError:
# catch ValueError and keep going
except OtherError:
# catch OtherError and keep going
# any other error breaks the loop
except ExpectedGeneratorError:
# handle generator exception here
except:
# handle more errors
You could extract the inner part into a worker function to keep things tidy.
Get the generator first?
try:
cg = complex_generator()
except Exception as e:
cg = [] # could alternatively have a success boolean here, and wrap the `for` loop below in an `if`
for value in cg:
...
I still think #Tomalak's answer is the most pythonic way to solve this problem. However I want to share the solution I ended up using, because both the complex_generator as well as the loop body might raise the same exception.
from typing import Iterable, Iterator, TypeVar
T = TypeVar("T")
def wrapper(iterable: Iterable[T]) -> Iterator[T | Exception]:
try:
for value in iterable:
yield value
except Exception as e:
yield e
for value in wrapper(complex_generator()):
if isinstance(value, Exception):
handle_generator_error(value)
else:
try:
process(value)
except Exception as e:
handle_loop_error(e)
Note: For more complex scenarios one might use match (structural pattern matching) and move the body error handling inside the process function.

Reraising an exception so it's handled in the same block

I have code that's a bit like this:
try:
# do stuff
except SomeSpecificException as sse:
if sse.some_property == some_special_value:
# handle the exception in a special way
else:
handle_exception_normally()
except:
handle_exception_normally()
I want to catch the specific exception and handle it in a special way, but only if it has a particular property. If it doesn't have that property, I want it to be handled just like any other exception (logging, screaming, etc.)
The code above works, but if possible, I want to avoid repeating handle_exception_normally() (DRY and all that).
Just putting raise in the else clause of the first except block does not work. A parent try block would catch that, but the catch-all clause in the same block will not.
I could nest two try blocks, but it's not very elegant; I'd rather just use
the code I have above.
Is there a better way?
Note that I'm using Python 3.
I would opt for:
try:
# do stuff
except Exception as e:
if e.args[0] == 'Discriminate Exception Here' and sse.some_property == some_special_value:
# handle the exception in a special way
else:
handle_exception_normally()
Moses Koledoye proposed:
try:
# do stuff
except Exception as e:
if getattr(e, 'some_property', None) == some_special_value:
# handle the exception in a special way
else:
handle_exception_normally()
Which is shorter but requires some_special_value to always be != None and attribute to be unique to your exception.
Examples of exception discrimination, with e.args[0]:
try:
5 / 0
except Exception as e:
print(e.args[0])
division by zero
With __class__.__name__:
try:
5 / 0
except Exception as e:
print(e.__class__.__name__)
ZeroDivisionError
With isinstance() (bit more CPU intensive) :
try:
5 / 0
except Exception as e:
isinstance(e, ZeroDivisionError)
True
I understand OP said they do not want to do this, but I'm throwing my lot in with the nested try block. I think it's the most readable way to go about this:
try:
try:
# do stuff
except SomeSpecificException as sse:
if sse.some_property == some_special_value:
# handle the exception in a special way
else:
raise
except:
handle_exception_normally()

Re-raising the exception doesn't work with "finally" clause

When I put in a finally clause, the raise statement in except doesn't work.
So the except block doesn't produce an Exception.
What am I missing? What do I need to do if I want to re-raise the Exception after the finally clause returns the value?
def test():
res = 1
try:
raise Exception
res = 2
except:
print('ha fallado')
raise
finally:
return res
test()
Solution:
def test():
res = 1
try:
raise Exception
res = 2
except:
print('ha fallado')
raise
finally:
# ... finally code that need to exec
pass
return res
print(test())
In this way if a Exception happened, the except block handle the exception and then raise it.
If not exception happened return the value.
Thanks for all the answers! So quick :)
Here is an answer that quotes the relevant part of the documentation:
The try clause is executed, including any except and else clauses. If an exception occurs in any of the clauses and is not handled, the exception is temporarily saved. The finally clause is executed. If there is a saved exception it is re-raised at the end of the finally clause. If the finally clause raises another exception, the saved exception is set as the context of the new exception. If the finally clause executes a return or break statement, the saved exception is discarded:
>>> def f():
... try:
... 1/0
... finally:
... return 42
...
>>> f()
42
P.S. I don't quite understand what you actually want to achieve; as noted in the top answer linked by zmbq, you can't really have both.
That's because you put a return statement in the finally block. It means you really want to return a value, even if an exception is thrown.
See here for more information.

How to catch all old-style class exceptions in 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...

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.

Categories