Get around raising IndexError - python

My code is as follows :
for p in qs:
set = None
try:
set = p.property.property_locations.all()
except IndexError:
pass
if set:
Problem is that when set is none it still throws IndexError from this part of django.db.models.query:
try:
qs = self._clone()
qs.query.set_limits(k, k + 1)
return list(qs)[0]
except self.model.DoesNotExist, e:
raise IndexError(e.args)
How to stop system from throwing this error and continuing to next element in for loop ?

In any case, there are two mistakes in your code:
set is a builtin (as you can see from SO's syntax highlighting), so by giving your variable that name you're shadowing the builtin for no purpose, which is at least bad practice, and likely to cause issues later in the code.
The canonical way to check if set is not None is by writing: if set is not None
Better yet, the canonical way to write that code snippet is:
try:
[code that might raise an exception]
except Error:
[code that handles the exception]
else:
[code that executes when no exception was raised]
(substitute Error for the actual exception, of course)
That way you don't even have to check 'set' at that point.

Related

Python: Re-displaying errors together after being ignored

I am using a method that raises a KeyError. I would like to run that through a for loop and then display all these errors together at once when it's done with the loop. Is that possible ?
I am doing a Try except as this post indicates in order to ignore the KeyError(s).
bad_list = []
for i in range (10):
try:
bad_list.append(checkermethod(i)) #checker method raises TypeError when called
except KeyError:
continue
if bad_list:
raise KeyError('\n'.join(bad_list))
I am trying to catch these errors by appending a list, but it's always empty, so it's not really appending anything. This makes sense since I am actually ignoring the errors, but is there any idea on how to do that in another way?
I found the solution:
bad_list = []
for i in range (10):
try:
checkermethod(i) #checker method raises TypeError when called
except KeyError as e:
bad_list.append(e.args[0])
if bad_list:
raise KeyError('\n'.join(bad_list))

re-raising exception doesn't work as expected

I have this rather intricate try except block:
try:
self.sorting = sys.argv[1]
try:
test_sorting_var = int(self.sorting)
if test_sorting_var < 1:
print "Sorting column number not valid."
raise ValueError
else:
self.sorting = test_sorting_var
except ValueError:
print "There's a problem with the sorting value provided"
print "Either the column doesn't exists or the column number is invalid"
print "Please try a different sorting value or omit it."
sys.exit(1)
except:
if self.sorting not in self.output_table.column_headers:
print "Sorting column name not valid."
raise ValueError
except:
pass
Basically I'm checking:
If there's a sys.argv[1]
If so, try it as int, and see if it's less than 1
If int fails, test it as string
In both 2+3, if the tests don't succeed, I'm raising a ValueError that should be caught in the except ValueError block and it does as expected:
Sorting column number not valid.
There's a problem with the sorting value provided
Either the column doesn't exists or the column number is invalid
Please try a different sorting value or omit it.
BUT! The sys.exit(1) is not invoked and the program just continues.
How can I fix it and even make it more readable?
In the last two lines you catch any exception:
except:
pass
This includes the exception SystemExit, which is raised by sys.exit.
To fix this, only catch exceptions deriving from Exception, which
SystemExit does not:
except Exception:
pass
In general, it's (almost) never a good idea to do a bare except, always catch Exception, or if possible, something more specific.
The builtint sys.exit() raises a SystemExit-Exception. As you are catching any type of exception when you don't define the Exception to catch (except: without an Exception Type) the SystemExit gets also caught. Ultimately the function will run until the last line where you wrote pass.
Best thing to do is to always catch specific Exceptions and never ever catch all Exceptions with an except:.
Furthermore you should put the check if self.sorting is not in self.output_table.column_headers outside the try catch where you check for a valid self.sorting.
From the documentation for sys.exit:
Exit from Python. This is implemented by raising the SystemExit exception, so cleanup actions specified by finally clauses of try statements are honored, and it is possible to intercept the exit attempt at an outer level.
This means that the outer try except loop is catching the SystemExit exception and causing it to pass. You can add this exception to the outer block and call it again.
I think I would do something like this:
import sys
def MyClass(object):
def method(self, argv, ...):
# ...
if len(argv) < 2:
raise RuntimeError("Usage: {} <sorting column>".format(argv[0]))
sorting = argv[1]
try:
self.sorting = int(sorting)
except ValueError:
try:
self.sorting = self.output_table.column_headers.index(sorting)
except ValueError:
raise ValueError("Invalid sorting column '{}'.".format(sorting))
# ...
try:
# ...
obj.method(sys.argv, ...)
except Exception as e:
sys.exit(e.message)
It's okay to ask for forgiveness instead of permission when it makes things easier (for example to parse a number), but if you need to make sure if sys.argv has enough elements just check it, it will make the program flow clearer.
Avoid using sys.exit within regular code, try to use it only in the outermost levels. For the most part, it is generally better to let exceptions bubble up and catch them at top level or let them crash the program if necessary.
Do make use of exception parameters to store error information, you can decide at a later point whether to print the error, log it, show it in a popup, ...
Instead of using sys.argv directly from within a class, you can pass it as an argument to the method/constructor, it will make the code easier to test and more flexible towards the future.

Else not raising errors in try-except-else

I'm working with a special try-except-else block in python where I try to fetch an value and if I fail I try to create it to use later.
However, the creation process is not perfect (it actually fetches from the internet and might fail for several reasons) and I noticed that when this fails it is not raised. The only information I get is that the value is not defined
NameError: name 'value' is not defined
Since the error can be many, I would very much appreciate to see the full trackback for the error in the else clause
Please note: all tries can raise KeyError and the instantiation process cannot raise this error, it's always something else. Here is a sample code:
try:
value = _list[key]
except KeyError:
try:
number = kwargs['number'] # A number might be parsed via kwargs
except KeyError:
clean_everything()
value = None
raise KeyError('Value not found! ' +
'Need a number to create new instance!')
else:
value = Value(number=number) # This instantiation can raise other errors!
_list[homeTeam] = _listnumber[number] = value # Update lists for future reference.
finally:
print value
Anyone got any ideas on why the else clause is not raising? Is there a better way to write this?
Thanks,
EDIT: Added treatment for value inside the nested try.
This is leading me to believe that nested tries doesn't work as the nested errors will only be raised after the outer-most finally.
i.e. inner errors are raised only after the outer try is completed.
This might lead to a new question: how can I properly raise an error inside an except clause?
Trying to access value without first defining it indeed raises NameError. If KeyError is raised because key is not in _list, then value will never get defined in the try block. Because you redefine value in both of the except blocks, this should be OK there. However, your finally block does not redefine value before accessing it, so you would get a NameError there in the following cases:
value = _list[key] raises an error other than KeyError (e.g. NameError when _list is not defined)
clean_everything() raises any error
value = Value(number=number) raises any error
You can define value before the try block so that it is always defined no matter what happens inside the try block.

What is preferable way to handle exceptions?

If I'm not sure at something while writing some code I'm trying to read The Zen of Python once more. For this time those lines hesitate me.
Errors should never pass silently.
Unless explicitly silenced.
At current code I have some functions which might look like this:
def add_v_1(a, b):
return a + b
And all calls for them like:
c = add_v_1(7, [])
Exception for such code will bubble up and caught at upper layers.
But should it be like this?
add_v_1 can raise TypeError exception and I want to recover from it.
So, the possible call of function would be:
try:
c = add_v_1(7, [])
except TypeError:
print "Incorrect types!"
But for every call, I should do that exception handling. Which looks to heavy.
So, I can do:
def add_v_2(a, b):
try:
return a + b
except TypeError:
print "Incorrect types!"
and a call would be:
c = add_v_2(7, [])
which looks cleaner.
Seems all of those approaches follow The Zen of Python but which one of them is better choice?
With reference to your example, it's debatable as to whether you should catch the exception inside the function. Doing so will return None from the function, which then burdens the calling code with checking the return value of the function, and treating None as an error. It effectively replaces exception handling with error checking. The former is generally more Pythonic.
You should ask whether it makes sense to catch an error such as attempting to add 2 completely different data types. Doing so in this case would seem to be a programming error, not really the sort of thing that you would expect during normal execution.
And what could you do to handle such an error? There doesn't seem to be any useful value that could be returned within the domain of the function's expected output... other than None to signal that a result could not be produced. But the calling code still has to perform some kind of error checking... so it might as well just handle an exception - at least it only has to handle that once.
But the example is contrived, and it's difficult to give blanket advice. In this particular situation, for the reasons above, I would allow the exception to propagate to the calling code and handle it there.
You should handle the except when you are able to recover from it. If you try to add two values with incompatible type there is nothing you could do to recover from that (without further context).
Lets assume you wrote an IntegerWrapper class and your function "add_v_2" should generally try to concatenate two value.
def add_v_2(a, b):
try:
return a + b
except TypeError as e:
if isinstance(a, IntegerWrapper):
return str(a) + b
else:
print("I dont know how to handle this type: " + type(a).__name__)
# reraise the error so the caller can handle it
raise
This would try to recover from a being of the "wrong type", but if you know how to recover from it. If it doesn't know (a is of another type) it reraises the Exception so someone who know how this can be handled sees the error.
(Of course that implementation contains bugs, it's not meant to be a "good implementation")
Input:
def add_v_2(a, b):
try:
return a + b
except Exception as e:
print str(e)
c = add_v_2(7, [])
print (c)
Output:
unsupported operand type(s) for +: 'int' and 'list'
None

Returning error string from a function in python

I have a class function in Python that either returns a success or a failure, but in case of a failure I want it to send a specific error string back. I have 3 approaches in mind:
Pass in an variable error_msg to the function originally set to None and in case of an error, it gets set to the error string. eg:
if !(foo(self, input, error_msg)):
print "no error"
else:
print error_msg
Return a tuple containing a bool and error_msg from the function.
I raise an exception in case of an error and catch it in the calling code. But since I don't see exceptions being used often in the codebase I am working on, so was not too sure about taking this approach.
What is the Pythonic way of doing this?
Create your own exception and raise that instead:
class MyValidationError(Exception):
pass
def my_function():
if not foo():
raise MyValidationError("Error message")
return 4
You can then call your function as:
try:
result = my_function()
except MyValidationError as exception:
# handle exception here and get error message
print exception.message
This style is called EAFP ("Easier to ask for forgiveness than permission") which means that you write the code as normal, raise exceptions when something goes wrong and handle that later:
This common Python
coding style assumes the existence of valid keys or attributes and
catches exceptions if the assumption proves false. This clean and fast
style is characterized by the presence of many try and except
statements. The technique contrasts with the LBYL style common to many
other languages such as C.
Raise an error:
if foo(self, input, error_msg):
raise SomethingError("You broke it")
And handle it:
try:
something()
except SomethingError as e:
print str(e)
It's the Pythonic approach and the most readable.
Returning a tuple like (12, None) may seem like a good solution, but it's hard to keep track of what each method returns if you're not consistent. Returning two different data types is even worse, as it will probably break code that assumes a constant data type.

Categories

Resources