cgitb vs traceback

R

Robin Becker

def raise_an_error():
a = 3
b = 4
c = 0
try:
a = a/c
except:
import sys, cgitb, traceback, inspect
tbt,tbv,tb = sys.exc_info()
print 'traceback\n',''.join(traceback.format_exception(tbt,tbv,tb))
print '\n\ncgitb\n',cgitb.text((tbt,tbv,tb),1)

raise_an_error()


The above script gives the error location as line 6 using
traceback.format_exception, but when the same triplet is passed to cgitb
formatters the error is recorded as coming from the line where cgitb.text is
called (or cgitb.html). Is this not an error?

The entire output from the script is below. At the very end the original
standard traceback is repeated inside cgitb.text and differs from the nicely
formatted version.

##############################
C:\code\rlinfra\test_utils>\tmp\eee.py
traceback
Traceback (most recent call last):
File "C:\tmp\eee.py", line 6, in raise_an_error
a = a/c
ZeroDivisionError: integer division or modulo by zero



cgitb
ZeroDivisionError
Python 2.3.2: C:\Python\python.exe
Mon May 10 16:00:40 2004

A problem occurred in a Python script. Here is the sequence of
function calls leading up to the error, in the order they occurred.

C:\tmp\eee.py in raise_an_error()
11 print '\n\ncgitb\n',cgitb.text((tbt,tbv,tb),1)cgitb = <module 'cgitb' from 'C:\Python\lib\cgitb.pyc'>
cgitb.text = <function text at 0x008EE930>
tbt = <class exceptions.ZeroDivisionError at 0x00864CC0>
tbv = <exceptions.ZeroDivisionError instance at 0x008ECF80>
tb = <traceback object at 0x008ECB98>
ZeroDivisionError: integer division or modulo by zero
__doc__ = 'Second argument to a division or modulo operation was zero.'
__getitem__ = <bound method ZeroDivisionError.__getitem__ of
<...ptions.ZeroDivisionError instance at 0x008ECF80>>
__init__ = <bound method ZeroDivisionError.__init__ of
<exceptions.ZeroDivisionError instance at 0x008ECF80>>
__module__ = 'exceptions'
__str__ = <bound method ZeroDivisionError.__str__ of
<exceptions.ZeroDivisionError instance at 0x008ECF80>>
args = ('integer division or modulo by zero',)

The above is a description of an error in a Python program. Here is
the original traceback:

Traceback (most recent call last):
File "C:\tmp\eee.py", line 6, in raise_an_error
a = a/c
ZeroDivisionError: integer division or modulo by zero
##############################
 
R

Robin Becker

Robin said:
def raise_an_error():
a = 3
b = 4
c = 0
try:
a = a/c
except:
import sys, cgitb, traceback, inspect
tbt,tbv,tb = sys.exc_info()
print 'traceback\n',''.join(traceback.format_exception(tbt,tbv,tb))
print '\n\ncgitb\n',cgitb.text((tbt,tbv,tb),1)

raise_an_error()
...... the above script demonstrates a bug in the inspect module's getinnerframes
function which is using the frame f_lineno instead of the traceback's tb_lineno.

eg

from inspect.py:getinnerframes we see that the traceback is followed and the
frame only is passed to getframeinfo which then has to use frame.f_lineno.

tb.tb_frame.f_lineno==tb.tb_lineno is not always true.

What this means is that a wrong line of code can be cited for the error in the
returned lines. A fix is to allow getframeinfo to have an optional lineno passed
in which getinnerframes can set using tb.tb_lineno. If not set or None
getframeinfo can use frame.f_lineno as before.

def getframeinfo(frame, context=1):
"""Get information about a frame or traceback object.
........"""
if istraceback(frame):
frame = frame.tb_frame
if not isframe(frame):
raise TypeError('arg is not a frame or traceback object')

filename = getsourcefile(frame) or getfile(frame)
lineno = frame.f_lineno

........

def getinnerframes(tb, context=1):
"""Get a list of records for a traceback's frame and all lower frames.

Each record contains a frame object, filename, line number, function
name, a list of lines of context, and index within the context."""
framelist = []
while tb:
framelist.append((tb.tb_frame,) + getframeinfo(tb, context))
tb = tb.tb_next
return framelist
 
F

Fernando Perez

Robin said:
..... the above script demonstrates a bug in the inspect module's
getinnerframes function which is using the frame f_lineno instead of the
traceback's tb_lineno.

Have you reported this on SF yet? I think I now realize I've been bitten by
this myself recently a few times. Do you know if it's a new 2.3 bug, or has it
been present since 2.2?

I wonder if the fix could make it into 2.3.4 or not...

Best,

f
 
R

Robin Becker

Fernando said:
Robin Becker wrote:




Have you reported this on SF yet? I think I now realize I've been bitten by
this myself recently a few times. Do you know if it's a new 2.3 bug, or has it
been present since 2.2?

I wonder if the fix could make it into 2.3.4 or not...

Best,

f
No I'll mosy on over and see if it's known. I have a fix in place in our
code, but we had to modify it yesterday as we're delivering for 2.1.
 
R

Robin Becker

Robin Becker wrote:

......
No I'll mosy on over and see if it's known. I have a fix in place in our
code, but we had to modify it yesterday as we're delivering for 2.1.

I didn't find anything similar there so I submitted a bug report and the
patch I used. I think it's far too late for 2.3.4.

As to whether this problem occurs in 2.1 I'm not sure. I know we fixed
the fix in our 2.1 tests as it had a // operator in the code and that
won't work in 2.1. I'm not sure whether it works though as we need it
only with cgitb and I'm not sure that's even present in 2.1.
 
F

Fernando Perez

Robin said:
Robin Becker wrote:

.....

I didn't find anything similar there so I submitted a bug report and the
patch I used. I think it's far too late for 2.3.4.

Do you have the SF bug number handy? I'd like to track this one in detail, in
case it really is what is giving my ipython users problems. Push comes to
shove, I could always patch inspect.py 'live' for the users at import time,
that's the beauty of python :)

Regards,

f
 
R

Robin Becker

Fernando said:
Robin Becker wrote:




Do you have the SF bug number handy? I'd like to track this one in detail, in
case it really is what is giving my ipython users problems. Push comes to
shove, I could always patch inspect.py 'live' for the users at import time,
that's the beauty of python :)

Regards,

f
It's bug 954364. Your method is exactly what I did ie inject the patched
functions into inspect at run time. Python may not be so easy to patch
in future if altering other module's name spaces becomes harder.
 
F

Fernando Perez

Robin said:
It's bug 954364. Your method is exactly what I did ie inject the patched
functions into inspect at run time. Python may not be so easy to patch
in future if altering other module's name spaces becomes harder.

Many thanks, Robin. Indeed, I worry about module namespaces becoming
'protected', since I use a LOT the ability to inject things where I need them
at runtime. I suspect if they actually go ahead with this approach, IPython is
going to break in horrible ways.

I really hope this kind of thing is done _optionally_, but that python continues
to 'treat programmers as adults'. I know what I'm doing is hackish, but I do
it knowingly (and because I need to). So please, python, assume I'm old enough
to know how to handle a sharp blade and don't wrap it in foam for me. Sometimes
I need to cut things harder than a banana :)

Best,

f
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top