Else not raising errors in try-except-else - python

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.

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.

marching query does not exist in if statement

well go to the question. I make this query:
Puntuaciones.objects.filter(bar__id=b).get(usuario=v.usuario2)
This works perfect, but when i put this in a if statement, like this:
if(Puntuaciones.objects.filter(bar__id=b).get(usuario=v.usuario2)):
I have a problem, when the query returns a object Puntuaciones i haven't any problems, but when there isn't a result it throws me:
Exception Value: Puntuaciones matching query does not exist.
So my question is, How i can do a if statement for a query if this query can be unsuccessful.
I try with Q objects, with exists()(this just works for querysets... I dont know how make it work. Any suggestion? Thank you
get() is either returning an object or throws ObjectDoesNotExist exception, catch it with the help of try/except:
try:
Puntuaciones.objects.filter(bar__id=b).get(usuario=v.usuario2)
# do something if object was found
except Puntuaciones.DoesNotExist:
# do smth if nothing found
Another options is to use exists():
if Puntuaciones.objects.filter(bar__id=b, usuario=v.usuario2).exists():
# do something if object was found
I would suggest a try: except: pair. That way, when the exception is triggered, you will be in the appropriate location to perform the code. Note that you really should use the correct exception type in the setup. Note that if you want to skip processing in the except, you need to put in an explicit pass (python noop) statement. Otherwise you will get an indentation error.
try:
if(Puntuaciones.objects.filter(bar__id=b).get(usuario=v.usuario2)):
# put code in here
pass # dummy statement to be replaced by actual code.
except:
# Put exception code here.
pass

Python: variable "tricking" try-exception, but works for if statement

I know the title seems crazy, but it is true. Here is my predicament. First, I am still a beginner at Python so please be considerate. I am trying to test if a variable exists. Now the variable comes from a file that is parsed in yaml. Whenever I try this code,
if not name['foo']:
print "No name given."
return False
Python does as you would expect and returns false. However, when I try to change it to this code,
try:
name['foo']
except:
print "ERROR: No name given."
raise
the exception is never risen. I have searched and searched and could not find any questions or sites that could explain this to me. My only thought is that the parser is "tricking" the exception handler, but that doesn't really make sense to me.
I have made sure that there were no white spaces in the name field of the document I am parsing. The field has the format:
*name: foo
*ver: bar
Like I have said, I made sure that foo was completely deleted along with any whitespace between lines. If anyone could help, it would be greatly appreciated.
EDIT:
And I apologize for the negative logic in the if statement. The function has to go through a series of checks. The best way I could think of to make sure all the checks were executed was to return true at the very end and to return false if any individual check failed.
A few things:
That shouldn't throw an exception! You're doing name['foo'] in two places and expecting different behavior.
The name doesn't behave like a dictionary, if it did you would NOT get a return of False in the first example, you'd get an exception. Try doing this:
name = {}
name['foo']
Then you'll get a KeyError exception
Don't ever have an except: block! Always catch the specific exception you're after, like IndexError or whatever
I don't understand why you think it would raise an exception. The key evidently exists, otherwise the first snippet would not work. The value for that key is obviously some false-y value like False, None, [] or ''.
Python does as you would expect and returns false.
The exception (KeyError) will be thrown only if there is no key in a dictionary (assuming name is a dictionary). If you do
if not name['foo']:
and it does not throw an exception, then it means that "foo" is in name but the value evaluates to boolean false (it can be False, None, empty string "", empty list [], empty dictionary {}, some custom object, etc. etc.). Thus wrapping name['foo'] with try:except: is pointless - the key is there.

Get around raising IndexError

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.

Categories

Resources