I am having issues with a ValueError working the way I want.
I have a function that is returning a string but I do not want it too evaluate to a ValueError if it is not raised from the function
Sample Code
def test(a):
if a == a:
raise ValueError('There was a error # 2')
a = 'a'
if ValueError:
print "There was a error # 1"
test(a)
Output
There was a error # 1
Traceback (most recent call last):
File "/home/user/Test_1.py", line 13, in <module>
test(a)
File "/home/user/Test_1.py", line 5, in test
raise ValueError('There was a error # 2')
ValueError: There was a error # 2
Process finished with exit code 1
If I read the docs correctly it said it can be raised by a string, how do i prevent this behavior?
https://docs.python.org/2/library/exceptions.html#exceptions.IndexError
Not sure why it was working before but I made it more explicit and it works now. Also the first example was more vague and I was trying to catch error from a function that was in the library.
Sample Code
def test(a):
try:
if a == a:
pass
raise ValueError('There was a error # 2')
except Exception, e:
str(e)
return e
a = 'a'
b = test(a)
if type(b) == ValueError:
print b
Output
There was a error # 2
Process finished with exit code 0
Related
This question already has an answer here:
Why do I get a `NameError` (or `UnboundLocalError`) from using a named exception after the `except` block?
(1 answer)
Closed last month.
I wrote this small snippet in python2 (2.7.18) to catch the exception in a variable and it works
>>> ex = None
>>> try:
... raise Exception("test")
... except Exception as ex:
... print(ex)
...
test
>>> ex
Exception('test',)
>>>
>>> ex2 = None
>>> try:
... raise Exception("test")
... except Exception as ex2:
... print(ex2)
... finally:
... print(ex2)
...
test
test
When I run the same in python3 (3.10.8), I get NameError
>>> ex = None
>>> try:
... raise Exception("test")
... except Exception as ex:
... print(ex)
...
test
>>> ex
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'ex' is not defined. Did you mean: 'hex'?
>>>
>>> ex2 = None
>>> try:
... raise Exception("test")
... except Exception as ex2:
... print(ex2)
... finally:
... print(ex2)
...
test
Traceback (most recent call last):
File "<stdin>", line 6, in <module>
NameError: name 'ex2' is not defined
What is the reason for this? Is the new python3 compiler doing optimisation where None assignment doesn't mean anything or is the try/except clause doing some magic?
What is the workaround for this which works in both python2 and python3?
It's not a magic really. It's documented here:
When an exception has been assigned using as target, it is cleared at the end of the except clause. This is as if:
except E as N:
foo
was translated to
except E as N:
try:
foo
finally:
del N
And the reason:
Exceptions are cleared
because with the traceback attached to them, they form a reference
cycle with the stack frame, keeping all locals in that frame alive
until the next garbage collection occurs.
You can get the traceback object with ex.__traceback__.
What is the workaround for this which works in both python2 and
python3?
You have to explicitly assign it to a different name(something other than target in as target as it's gonna get deleted):
exc_object = None
try:
raise Exception("test")
except Exception as ex:
print(ex)
exc_object = ex
print(exc_object)
Note: This is only the case with except block and has nothing to do with as assignment statement as you can see in context managers: with...as... block for example.
So I have say 3 functions I would like to run. Each of them can fail. I would like to built try-except around them to:
let as many as possible out of 3 run AND
raise an error at the end if any of them failed. Is this possible?
The below code fails as operation D (in the middle fails) so E is never reached:
try:
c = 3 + 6
print(c)
except TypeError:
raise TypeError("Wrong type provided in operation C")
try:
d = 3 + '6'
print(d)
except TypeError:
raise TypeError("Wrong type provided in operation D")
try:
e = 7 + 5
print(e)
except TypeError:
raise TypeError("Wrong type provided in operation E")
def f1():
print("f1")
def f2():
raise TypeError
print("f2")
def f3():
print("f3")
err = None
for f in [f1, f2, f3]:
try:
f()
except TypeError as e:
# store first error
if not err:
err = e
if err:
raise err
Output:
f1
f3
[...]
TypeError
If your functions take arguments, you can loop over
[(f1, f1_args, f1_kwargs), (f2, f2_args, f2_kwargs), (f3, f3_args, f3_kwargs)]
Inspired by a comment I tried to come up with a nifty context manager that sort of raises all the exceptions in a nested fashion upon exiting. Comments are welcome.
class ErrorCollector:
def __init__(self):
self.errors = []
def exec(self, f, suppress_types=None, *args, **kwargs):
suppress_types = tuple(suppress_types) if suppress_types else ()
try:
return f(*args, **kwargs)
except suppress_types as e:
self.errors.append(e)
def _raise_all(self, errors):
if len(errors) == 1:
raise errors[0]
for e in errors:
try:
raise e
except type(e):
self._raise_all(errors[1:])
def __enter__(self):
return self
def __exit__(self, exctype, excinst, exctb):
if excinst is not None:
self.errors.append(excinst)
self._raise_all(self.errors)
def f1():
print('f1')
def f2():
raise TypeError('TypeError in f2')
print('f2')
def f3():
raise ValueError('ValueError in f3')
print('f3')
def f4():
raise TypeError('TypeError in f4')
print('f4')
def f5():
print('f5')
def f6():
raise ZeroDivisionError('ZeroDivisionError in f6')
print('f6')
def f7():
print('f7')
Now you can use:
suppress = [TypeError, ValueError]
with ErrorCollector() as ec:
for f in (f1, f2, f3, f4, f5, f6, f7):
ec.exec(f, suppress)
with the output:
f1
f5
[...]
TypeError: TypeError in f2
During handling of the above exception, another exception occurred:
[...]
ValueError: ValueError in f3
During handling of the above exception, another exception occurred:
[...]
TypeError: TypeError in f4
During handling of the above exception, another exception occurred:
[...]
ZeroDivisionError: ZeroDivisionError in f6
Note that f7 is not executed because the ZeroDivisionError was not suppressed.
Other responses have provided ad-hoc handlers of various manners. An interesting alternative if this is a recurring need is to build a context manager similar to contextlib.suppress, something along the lines of (untested):
class Suppressor:
def __init__(self, *to_suppress):
self.to_suppress = to_suppress # empty = suppress all
self.exceptions = []
def __enter__(self):
pass
def __exit__(self, etype, val, _):
if etype is not None:
# if the exception is selected
if not self.to_suppress or isinstance(val, self.to_suppress):
# store and suppress it
self.exceptions.append(val)
return True
# otherwise ignore
Usage:
suppressor = Suppressor(TypeError)
with suppressor:
c = 3 + 6
print(c) # 9
with suppressor:
d = 3 + '6' # error (suppressed)
print(d)
with suppressor:
e = 7 + 5
print(e) # 12
if suppressor.exceptions:
# TypeError("unsupported operand type(s) for +: 'int' and 'str'")
print(repr(suppressor.exceptions[0]))
with suppressor:
# ValueError: invalid literal for int() with base 10: 'a'
e = 7 + int('a')
The most simple would be:
errors = 0
try:
c = 3 + 6
print(c)
except TypeError:
errors +=1
try:
d = 3 + '6'
print(d)
except TypeError:
errors +=1
try:
e = 7 + 5
print(e)
except TypeError:
errors +=1
if errors!=0:
raise TypeError("Wrong type provided in some operation")
If you want to get which operation threw TypeError you can assign it in 3 different variable.
Hope this helps!
You could collect the exceptions. Then, you can actually reraise them rather than building a new exception, by having access to each.
exceptions = []
try:
raise ValueError("thing 1 error") # simulate error in first function
except ValueError as exc:
exceptions.append(exc)
try:
raise ValueError("thing 2 error") # simulate error in second function
except ValueError as exc:
exceptions.append(exc)
try:
raise ValueError("thing 3 error") # simulate error in third function
except ValueError as exc:
exceptions.append(exc)
You can then optionally raise a new exception. Something like:
if exceptions:
raise Exception("something went wrong")
Which gives:
Traceback (most recent call last):
File "./main.py", line 21, in <module>
raise Exception("something went wrong")
Exception: something went wrong
Or, you can directly access any or all of these exceptions. Something like:
raise exceptions[1]
Which gives:
Traceback (most recent call last):
File "./main.py", line 25, in <module>
raise exceptions[1]
File "./main.py", line 11, in <module>
raise ValueError("thing 2 error") # simulate error in second function
ValueError: thing 2 error
If I do the following in python
i = 0
assert i == 1, f"expected 1, got {i}"
The assert message is
Traceback (most recent call last):
...
assert i == 1, f"expected 1, got {i}"
How do I get it to show expected 1, got 0? It doesn't seem to expand the dynamic string first but treat it as a literal.
If you want just the single line printed, without the whole traceback, here's one way to handle it:
import sys
i = 0
try:
assert i == 1, f"expected 1, got {i}"
except AssertionError as e:
print(e)
# print(e, file=sys.stderr) # to print to stderr
sys.exit(1) # exit program with error
You could also intercept the system excepthook or something similar and alter how the traceback is printed out.
Here is working with an excepthook:
import sys
def assertion_excepthook(type, value, traceback):
if type is AssertionError:
print(value)
# with line number:
print(f"{traceback.tb_lineno}: {value}")
else:
sys.__excepthook__(type, value, traceback)
sys.excepthook = assertion_excepthook
i = 0
assert i == 1, f"expected 1, got {i}"
This solution is a little more overhead but it means you won't have to do several try/except blocks.
(This is a follow-up question to the post Python try/except: Showing the cause of the error after displaying my variables.)
I have the following script.py:
import traceback
def process_string(s):
"""
INPUT
-----
s: string
Must be convertable to a float
OUTPUT
------
x: float
"""
# validate that s is convertable to a float
try:
x = float(s)
return x
except ValueError:
print
traceback.print_exc()
if __name__ == '__main__':
a = process_string('0.25')
b = process_string('t01')
c = process_string('201')
Upon execution of script.py, the following message is printed in the terminal window:
Traceback (most recent call last):
File "/home/user/Desktop/script.py", line 20, in process_string
x = float(s)
ValueError: could not convert string to float: t01
May I ask if there is a way for traceback.print_exc() to also print in the terminal window which instruction inside the if-main threw the exception which was caught by the try-except clause?
What about this?
import traceback
def process_string(s):
"""
INPUT
-----
s: string
Must be convertible to a float
OUTPUT
------
x: float
"""
return float(s)
if __name__ == '__main__':
try:
a = process_string('0.25')
b = process_string('t01')
c = process_string('201')
except ValueError:
print
traceback.print_exc()
I am reading some python code written a while ago, and found this:
try:
# do some stuff
except 0:
# exception handling stuff
And I'm just not sure what except 0 means? I do have my guesses: Supposed to catch nothing i.e. let the exception propagate or it could be some sort of switch to turn debugging mode on and off by removing the 0 which will then catch everything.
Can anyone lend some insight? a google search yielded nothing...
Thanks!
Some sample code (by request):
try:
if logErrors:
dbStuffer.setStatusToError(prop_id, obj)
db.commit()
except 0:
traceback.print_exc()
From what I understand, This is very useful for debugging purposes (Catching the type of exception)
In your example 0 acts as a placeholder to determine the type of exception.
>>> try:
... x = 5/1 + 4*a/3
... except 0:
... print 'error'
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
NameError: name 'a' is not defined
>>> try:
... x = 5/0 + 4*a/3
... except 0:
... print 'error'
...
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
ZeroDivisionError: integer division or modulo by zero
In the first case, the exception is NameError and ZeroDivisionError in the second.
the 0 acts as a placeholder for any type of exception being caught.
>>> try:
... print 'error'
... except:
...
KeyboardInterrupt
>>> try:
... x = 5/0 + 4*a/3
... except:
... print 'error'
...
error
From the Python docs:
"[...] the [except] clause matches the exception if the resulting object is “compatible” with the exception. An object is compatible with an exception if it is the class or a base class of the exception object, or a tuple containing an item compatible with the exception."
In effect the type of the expression is used to determine whether the except clauses matches the exception. As 0 is of an integer type, and exception of that type would match.
Since integers cannot be raised as exception, this is a disabled exceptclass that will not catch anything.