Note the following Python code:
import pytest
def test_validate_number():
number = 2
try:
verify_number(number)
except AssertionError as exc:
raise exc
def verify_number(number):
assert number == 3, 'Incorrect number'
When executing this code and of course the exception is caught the args tuple value is shown below, which is fine with me because I need the assert values assert 2 == 3
'Incorrect number
assert 2 == 3'
The problem is when the same code is executed and the exception is caught from another module, for example:
helpers.py
def verify_number(number):
assert number == 3, 'Incorrect number'
test_numbers.py
import pytest
from tests.helpers import verify_number
def test_validate_number():
number = 2
try:
verify_number(number)
except AssertionError as exc:
raise exc
When the exception is caught from another module like this, the exception args tuple only has the assertion message and not the assert values like this:
'Incorrect number'
Why does this happen? I need those values assert 2 == 3
It's because it has caught the AssertionError from verify_number and the value stored in exc is the text Incorrect number. It then raises that exception.
To get the value of number, try this:
def verify_number(number):
assert number == 3, f'Incorrect number: {number} != 3'
And it will then output Incorrect number: 2 != 3
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
(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.
How can i get full traceback in the following case, including the calls of func2 and func functions?
import traceback
def func():
try:
raise Exception('Dummy')
except:
traceback.print_exc()
def func2():
func()
func2()
When i run this, i get:
Traceback (most recent call last):
File "test.py", line 5, in func
raise Exception('Dummy')
Exception: Dummy
traceback.format_stack() is not what i want, as need traceback object to be passed to a third party module.
I am particularly interested in this case:
import logging
def func():
try:
raise Exception('Dummy')
except:
logging.exception("Something awful happened!")
def func2():
func()
func2()
In this case i am getting:
ERROR:root:Something awful happened!
Traceback (most recent call last):
File "test.py", line 9, in func
raise Exception('Dummy')
Exception: Dummy
As mechmind answered, the stack trace consists only of frames between the site where the exception was raised and the site of the try block. If you need the full stack trace, apparently you're out of luck.
Except that it's obviously possible to extract the stack entries from top-level to the current frame—traceback.extract_stack manages it just fine. The problem is that the information obtained by traceback.extract_stack comes from direct inspection of stack frames without creating a traceback object at any point, and the logging API requires a traceback object to affect traceback output.
Fortunately, logging doesn't require an actual traceback object, it requires an object that it can pass to the formatting routines of the traceback module. traceback doesn't care either—it only uses two attributes of the traceback, the frame and the line number. So, it should be possible to create a linked list of duck-typed faux-traceback objects and pass it off as the traceback.
import sys
class FauxTb(object):
def __init__(self, tb_frame, tb_lineno, tb_next):
self.tb_frame = tb_frame
self.tb_lineno = tb_lineno
self.tb_next = tb_next
def current_stack(skip=0):
try: 1/0
except ZeroDivisionError:
f = sys.exc_info()[2].tb_frame
for i in xrange(skip + 2):
f = f.f_back
lst = []
while f is not None:
lst.append((f, f.f_lineno))
f = f.f_back
return lst
def extend_traceback(tb, stack):
"""Extend traceback with stack info."""
head = tb
for tb_frame, tb_lineno in stack:
head = FauxTb(tb_frame, tb_lineno, head)
return head
def full_exc_info():
"""Like sys.exc_info, but includes the full traceback."""
t, v, tb = sys.exc_info()
full_tb = extend_traceback(tb, current_stack(1))
return t, v, full_tb
With these functions in place, your code only requires a trivial modification:
import logging
def func():
try:
raise Exception('Dummy')
except:
logging.error("Something awful happened!", exc_info=full_exc_info())
def func2():
func()
func2()
...to give the expected output:
ERROR:root:Something awful happened!
Traceback (most recent call last):
File "a.py", line 52, in <module>
func2()
File "a.py", line 49, in func2
func()
File "a.py", line 43, in func
raise Exception('Dummy')
Exception: Dummy
Note that the faux-traceback objects are fully usable for introspection—displaying local variables or as argument to pdb.post_mortem()—because they contain references to real stack frames.
This is based on user4815162342's answer, but a bit more minimalistic:
import sys
import collections
FauxTb = collections.namedtuple("FauxTb", ["tb_frame", "tb_lineno", "tb_next"])
def full_exc_info():
"""Like sys.exc_info, but includes the full traceback."""
t, v, tb = sys.exc_info()
f = sys._getframe(2)
while f is not None:
tb = FauxTb(f, f.f_lineno, tb)
f = f.f_back
return t, v, tb
It avoids throwing the dummy exception, at the cost of requiring the usage of sys._getframe(). It assumes being used in the except clause where the exception was caught, as it goes up two stack frames (full_exc_info and the function that calls full_exc_info – that would be the function that calls the raising code, and as such is already included in the original traceback).
This gives the same output as the code in user4815162342's answer.
If you don't mind the slight differences in formatting, you can also use
import logging
def func():
try:
raise Exception('Dummy')
except:
logging.exception("Something awful happened!", stack_info=True)
def func2():
func()
func2()
which results in
ERROR:root:Something awful happened!
Traceback (most recent call last):
File "test.py", line 5, in func
raise Exception('Dummy')
Exception: Dummy
Stack (most recent call last):
File "test.py", line 12, in <module>
func2()
File "test.py", line 10, in func2
func()
File "test.py", line 7, in func
logging.exception("Something awful happened!", stack_info=True)
In this case, you'll get a trace from the try to the exception, and a second from the root call to the location of the logging call.
Stack trace is collected when exception bubbles up. So you should print traceback on top of desired stack:
import traceback
def func():
raise Exception('Dummy')
def func2():
func()
try:
func2()
except:
traceback.print_exc()
i have written a module that writes a more complete traceback
The module is here documentation is docs
(also you can get the module from pypi
sudo pip install pd
)
To catch and pring exceptions do the following:
import pd
try:
<python code>
except BaseException:
pd.print_exception_ex( follow_objects = 1 )
The stack trace looks like this one here:
Exception: got it
#1 def kuku2(self = {'a': 42, 'b': [1, 2, 3, 4]}, depth = 1) at t test_pd.py:29
Calls next frame at:
raise Exception('got it') at: test_pd.py:29
#2 def kuku2(self = {'a': 42, 'b': [1, 2, 3, 4]}, depth = 2) at test_pd.py:28
Calls next frame at:
self.kuku2( depth - 1 ) at: test_pd.py:28
#3 def kuku2(self = {'a': 42, 'b': [1, 2, 3, 4]}, depth = 3) at test_pd.py:28
Calls next frame at:
self.kuku2( depth - 1 ) at: test_pd.py:28
#4 def kuku2(self = {'a': 42, 'b': [1, 2, 3, 4]}, depth = 4) at test_pd.py:28
Calls next frame at:
self.kuku2( depth - 1 ) at: test_pd.py:28
#5 def kuku2(self = {'a': 42, 'b': [1, 2, 3, 4]}, depth = 5) at test_pd.py:28
Calls next frame at:
self.kuku2( depth - 1 ) at: test_pd.py:28
#6 def kuku2(self = {'a': 42, 'b': [1, 2, 3, 4]}, depth = 6) at test_pd.py:28
Calls next frame at:
self.kuku2( depth - 1 ) at: test_pd.py:28
#7 def main() at test_pd.py:44
Local variables:
n = {'a': 42, 'b': [1, 2, 3, 4]}
Calls next frame at:
pd.print_exception_ex( follow_objects = 1 ) at: test_pd.py:44
follow_objects = 0 will not print out object content (with complex data structures follow_objects can take a lot of time).
There's some more information that could be extracted from the traceback, and I sometimes prefer a neater, more 'logical' information instead of multi-line blob with files, line numbers and code snippetsgiven by traceback. Preferably one line should say all the essentials.
To achieve this I use following function:
def raising_code_info():
code_info = ''
try:
frames = inspect.trace()
if(len(frames)):
full_method_name = frames[0][4][0].rstrip('\n\r').strip()
line_number = frames[1][2]
module_name = frames[0][0].f_globals['__name__']
if(module_name == '__main__'):
module_name = os.path.basename(sys.argv[0]).replace('.py','')
class_name = ''
obj_name_dot_method = full_method_name.split('.', 1)
if len(obj_name_dot_method) > 1:
obj_name, full_method_name = obj_name_dot_method
try:
class_name = frames[0][0].f_locals[obj_name].__class__.__name__
except:
pass
method_name = module_name + '.'
if len(class_name) > 0:
method_name += class_name + '.'
method_name += full_method_name
code_info = '%s, line %d' % (method_name, line_number)
finally:
del frames
sys.exc_clear()
return code_info
It gives . and line number, e.g.:
(example module name: test.py):
(line 73:)
def function1():
print 1/0
class AClass(object):
def method2(self):
a = []
a[3] = 1
def try_it_out():
# try it with a function
try:
function1()
except Exception, what:
print '%s: \"%s\"' % (raising_code_info(), what)
# try it with a method
try:
my_obj_name = AClass()
my_obj_name.method2()
except Exception, what:
print '%s: \"%s\"' % (raising_code_info(), what)
if __name__ == '__main__':
try_it_out()
test.function1(), line 75: "integer division or modulo by zero"
test.AClass.method2(), line 80: "list assignment index out of range"
Which might be slightly neater in some use-cases.