Reputation: 546
How to retrieve the line of code (not the line number) that causes an exception?
This is an attempt.
import sys, inspect
try:
1 / 0
except Exception as e:
exc_type, exc_obj, exc_tb = sys.exc_info()
code = str(inspect.getsourcelines(exc_tb.tb_frame.f_code))
print(code)
It returns the first line of the script, not the line that causes the exception.
(['import sys, inspect\n'], 1)
Upvotes: 4
Views: 373
Reputation: 3255
To add to spinx's answer, there are attributes in every FrameInfo
object
So we can make the code more readable by using them:
import sys, inspect
try:
y = 2
a = 1 / 0
except Exception as e:
exception_occr_at_file = inspect.trace()[0].filename
line_no = inspect.trace()[0].lineno
code = inspect.trace()[0].code_context
print(exception_occr_at_file)
print(line_no)
print(code)
I also wasn't too happy with the random indexing at 0
for the frames. Reading the description of inspect.info
, it doesn't sound like the correct position is being indexed.
inspect.trace(context=1)
Return a list ofFrameInfo
objects for the stack between the current frame and the frame in which an exception currently being handled was raised in. The first entry in the list represents the caller; the last entry represents where the exception was raised.
0
will give the line of the caller, not the thrower. A nice example is found here. (I'm copying it here for easy of use.)
import sys
import inspect
from pprint import pprint
def errorer():
raise Exception('foo')
def syser():
try:
errorer()
except Exception, e:
tb = sys.exc_info()[2]
print tb.tb_frame
print tb.tb_lasti
print tb.tb_lineno
print tb.tb_next
def inspecter():
try:
errorer()
except Exception, e:
pprint(inspect.trace())
With the following output:
>>> syser()
<frame object at 0x1441240>
6
10
<traceback object at 0x13eb3b0>
>>> inspecter()
[(<frame object at 0x14a5590>,
'/tmp/errors.py',
22,
'inspecter',
None,
None),
(<frame object at 0x14a21b0>,
'/tmp/errors.py',
8,
'errorer',
None,
None)]
We can clearly see that indexing at 0
gives us the line the function errorer
is called in inspecter
and -1
gives us the point where we throw the exception.
So if we want to know which line throws the exception, -1
is correct, if we however want to know the root of our call tree of a failing function/object, 0
is correct.
Upvotes: 0
Reputation: 10729
Below codes works, but it is inflexible. Someone else may have better solution.
import sys, inspect
try:
y = 2
a = 1 / 0
except Exception as e:
exception_occr_at_file = inspect.trace()[0][1]
line_no = inspect.trace()[0][2]
code = inspect.trace()[0][4]
print(exception_occr_at_file)
print(line_no)
print(code)
#Ouput:
C:\Users\jianc\Desktop\test\test_print.py
4
[' a = 1 / 0\n']
Upvotes: 2