Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Python > Deeper tracebacks?

Reply
Thread Tools

Deeper tracebacks?

 
 
brooklineTom
Guest
Posts: n/a
 
      12-10-2008
I want my exception handler to report the method that originally
raised an exception, at the deepest level in the call-tree. Let give
an example.

import sys, traceback
class SomeClass:
def error(self):
"""Raises an AttributeError exception."""
int(3).zork()

def perform_(self, aSelector):
try:
aMethod = getattr(self, aSelector, None)
answer = apply(aMethod, [], {})
except: AttributeError, anAttributeErrorException:
aRawStack = traceback.extract_stack()
answer = None

When I call "perform_" (... SomeClass().perform_('error')), I want to
collect and report the location *within the method ("error") that
failed*. The above code reports the location of "perform_", and no
deeper in the call tree.

Anybody know how to accomplish this?
 
Reply With Quote
 
 
 
 
Gabriel Genellina
Guest
Posts: n/a
 
      12-10-2008
En Wed, 10 Dec 2008 16:59:16 -0200, brooklineTom <(E-Mail Removed)>
escribió:

> I want my exception handler to report the method that originally
> raised an exception, at the deepest level in the call-tree. Let give
> an example.


That's the default behavior, you don't have to do anything special.

> import sys, traceback
> class SomeClass:
> def error(self):
> """Raises an AttributeError exception."""
> int(3).zork()
>
> def perform_(self, aSelector):
> try:
> aMethod = getattr(self, aSelector, None)
> answer = apply(aMethod, [], {})
> except: AttributeError, anAttributeErrorException:
> aRawStack = traceback.extract_stack()
> answer = None


(I assume you're using Python < 3.0)
Use the 3-names form of the except statement:

try:
aMethod = getattr(self, aSelector, None)
answer = aMethod()
except AttributeError, e, tb:
# the tb variable holds the traceback up to the error
# the same thing you see printed by Python when
# an unhandled error happens
answer = None


Alternatively, you can obtain the same thing with sys.exc_info()[2]
Remember to delete any reference to the traceback object as soon as you're
done with it; see http://docs.python.org/library/sys.html#sys.exc_info

--
Gabriel Genellina

 
Reply With Quote
 
 
 
 
brooklineTom
Guest
Posts: n/a
 
      12-10-2008
On Dec 10, 5:03 pm, "Gabriel Genellina" <(E-Mail Removed)>
wrote:
> En Wed, 10 Dec 2008 16:59:16 -0200, brooklineTom <(E-Mail Removed)>
> escribió:
>
> > I want my exception handler to report the method that originally
> > raised an exception, at the deepest level in the call-tree. Let give
> > an example.

>
> That's the default behavior, you don't have to do anything special.
>
> > import sys, traceback
> > class SomeClass:
> > def error(self):
> > """Raises an AttributeError exception."""
> > int(3).zork()

>
> > def perform_(self, aSelector):
> > try:
> > aMethod = getattr(self, aSelector, None)
> > answer = apply(aMethod, [], {})
> > except: AttributeError, anAttributeErrorException:
> > aRawStack = traceback.extract_stack()
> > answer = None

>
> (I assume you're using Python < 3.0)
> Use the 3-names form of the except statement:
>
> try:
> aMethod = getattr(self, aSelector, None)
> answer = aMethod()
> except AttributeError, e, tb:
> # the tb variable holds the traceback up to the error
> # the same thing you see printed by Python when
> # an unhandled error happens
> answer = None
>
> Alternatively, you can obtain the same thing with sys.exc_info()[2]
> Remember to delete any reference to the traceback object as soon as you're
> done with it; seehttp://docs.python.org/library/sys.html#sys.exc_info
>
> --
> Gabriel Genellina


I'm using Python 2.5.

As I understand it, "aRawStack" (above) has the same information as
sys.exc_info()[2].

The deepest entry in aRawStack is the perform_ invocation. The
contents of the two bottom-most stack frames are:
>>> aRawStack[8][3]

"answer = anObject.perform_('error')"
>>> aRawStack[9][3]

'aRawStack = traceback.extract_stack()'


By the time the handler is called, "zork" -- the method that was
called when the exception was raised, and "error", the method that
invoked zork, have already been removed from the stack.

In this example, I only show one call for simplicity. In practice, the
method being invoked by perform_ may nest calls arbitrarily deeply. I
know, by being in the exception handler, that an exception happened.
What I need to know is which nested call raised it.
 
Reply With Quote
 
brooklineTom
Guest
Posts: n/a
 
      12-11-2008
On Dec 10, 10:49 pm, "Chris Rebert" <(E-Mail Removed)> wrote:
> On Wed, Dec 10, 2008 at 3:50 PM, brooklineTom <(E-Mail Removed)> wrote:
> > On Dec 10, 5:03 pm, "Gabriel Genellina" <(E-Mail Removed)>
> > wrote:
> >> En Wed, 10 Dec 2008 16:59:16 -0200, brooklineTom <(E-Mail Removed)>
> >> escribió:

>
> >> > I want my exception handler to report the method that originally
> >> > raised an exception, at the deepest level in the call-tree. Let give
> >> > an example.

>
> >> That's the default behavior, you don't have to do anything special.

>
> >> > import sys, traceback
> >> > class SomeClass:
> >> > def error(self):
> >> > """Raises an AttributeError exception."""
> >> > int(3).zork()

>
> >> > def perform_(self, aSelector):
> >> > try:
> >> > aMethod = getattr(self, aSelector, None)
> >> > answer = apply(aMethod, [], {})
> >> > except: AttributeError, anAttributeErrorException:
> >> > aRawStack = traceback.extract_stack()
> >> > answer = None

>
> >> (I assume you're using Python < 3.0)
> >> Use the 3-names form of the except statement:

>
> >> try:
> >> aMethod = getattr(self, aSelector, None)
> >> answer = aMethod()
> >> except AttributeError, e, tb:
> >> # the tb variable holds the traceback up to the error
> >> # the same thing you see printed by Python when
> >> # an unhandled error happens
> >> answer = None

>
> >> Alternatively, you can obtain the same thing with sys.exc_info()[2]
> >> Remember to delete any reference to the traceback object as soon as you're
> >> done with it; seehttp://docs.python.org/library/sys.html#sys.exc_info

>
> >> --
> >> Gabriel Genellina

>
> > I'm using Python 2.5.

>
> > As I understand it, "aRawStack" (above) has the same information as
> > sys.exc_info()[2].

>
> > The deepest entry in aRawStack is the perform_ invocation. The
> > contents of the two bottom-most stack frames are:
> >>>> aRawStack[8][3]

> > "answer = anObject.perform_('error')"
> >>>> aRawStack[9][3]

> > 'aRawStack = traceback.extract_stack()'

>
> > By the time the handler is called, "zork" -- the method that was
> > called when the exception was raised, and "error", the method that
> > invoked zork, have already been removed from the stack.

>
> There is no zork() method, so it *can't have been called* and
> therefore *can't be in the traceback*. The error lies in the method
> that's trying to call a _nonexistent_ method, and that's where Python
> reports the error.
>
> Recall that:
> x.zork()
>
> is equivalent to:
> _z = x.zork #error occurs here, in the attribute lookup
> _z() #Python never gets here
>
> So no call takes place because you get an AttributeError before Python
> can get any further. zork() would only in the traceback if (1) it was
> looked up and called successfully [not the case here] and (2) an error
> occurred in zork()'s method body [again, not the case because it's not
> defined].
>
> Cheers,
> Chris
>
> --
> Follow the path of the Iguana...http://rebertia.com


I understand that there is no method named "zork". The attempted call
to zork occurred in the method named "error", *not* the method named
"perform_". I suggest that the failing method is "error", and the
reported line number should be the line that contains "int(3).zork".

Specifically, I think that aRawStack should contain the following:

>>> aRawStack[8][3]

"answer = anObject.perform_('error')"

>>> aRawStack[9][3]

"answer = anObject.error()"

>>> aRawStack[10][3]

'aRawStack = traceback.extract_stack()'

The entry at aRawStack[9] is the stack frame that I suggest is
missing.

Thx,
Tom
 
Reply With Quote
 
R. Bernstein
Guest
Posts: n/a
 
      12-11-2008
brooklineTom <(E-Mail Removed)> writes:

> I want my exception handler to report the method that originally
> raised an exception, at the deepest level in the call-tree. Let give
> an example.
>
> import sys, traceback
> class SomeClass:
> def error(self):
> """Raises an AttributeError exception."""
> int(3).zork()
>
> def perform_(self, aSelector):
> try:
> aMethod = getattr(self, aSelector, None)
> answer = apply(aMethod, [], {})
> except: AttributeError, anAttributeErrorException:
> aRawStack = traceback.extract_stack()
> answer = None
>
> When I call "perform_" (... SomeClass().perform_('error')), I want to
> collect and report the location *within the method ("error") that
> failed*. The above code reports the location of "perform_", and no
> deeper in the call tree.
>
> Anybody know how to accomplish this?


extract_stack() without any arguments is getting this from the
*current frame* which as you noted doesn't have the last exception
info included which has been popped; variable sys.last_traceback has the frames
at the time of the exception, I think.

So in your code try changing:
aRawStack = traceback.extract_stack()
to
aRawStack = traceback.extract_stack(sys.last_traceback)
 
Reply With Quote
 
brooklineTom
Guest
Posts: n/a
 
      12-11-2008
BINGO! Give that man a CIGAR!

The specifics don't seem to be quite right (there is no
sys.last_traceback), but R.Bernstein put me directly on the correct
track. I misunderstood the traceback module documentation. OK, I just
plain didn't read it correctly, it's right there ("extract_stack():
Extract the raw traceback from the current stack frame."). The answer
is to use traceback.extract_tb (), called with sys.exc_info()[3] (the
stackframe that raised the exception).

Another sterling example of the benefits of reading the fine manual --
for comprehension this time.

Instead of:
aRawStack = traceback.extract_stack()
do this:
aRawStack = traceback.extract_tb(sys.exc_info()[2])

With this change, aRawStack contains the following:

>>> aRawStack[0][3]

'answer = apply(aMethod, [], {})'
>>> aRawStack[1][3]

'int(3).zork()'

This is *exactly* what I was seeking.

I appreciate all the responses, and especially appreciate the pointer
from R.Bernstein.

Thx,
Tom

On Dec 11, 4:49 am, (E-Mail Removed) (R. Bernstein) wrote:
> brooklineTom <(E-Mail Removed)> writes:
> > I want my exception handler to report the method that originally
> > raised an exception, at the deepest level in the call-tree. Let give
> > an example.

>
> > import sys, traceback
> > class SomeClass:
> > def error(self):
> > """Raises an AttributeError exception."""
> > int(3).zork()

>
> > def perform_(self, aSelector):
> > try:
> > aMethod = getattr(self, aSelector, None)
> > answer = apply(aMethod, [], {})
> > except: AttributeError, anAttributeErrorException:
> > aRawStack = traceback.extract_stack()
> > answer = None

>
> > When I call "perform_" (... SomeClass().perform_('error')), I want to
> > collect and report the location *within the method ("error") that
> > failed*. The above code reports the location of "perform_", and no
> > deeper in the call tree.

>
> > Anybody know how to accomplish this?

>
> extract_stack() without any arguments is getting this from the
> *current frame* which as you noted doesn't have the last exception
> info included which has been popped; variable sys.last_traceback has the frames
> at the time of the exception, I think.
>
> So in your code try changing:
> aRawStack = traceback.extract_stack()
> to
> aRawStack = traceback.extract_stack(sys.last_traceback)

 
Reply With Quote
 
Gabriel Genellina
Guest
Posts: n/a
 
      12-11-2008
En Thu, 11 Dec 2008 07:49:42 -0200, R. Bernstein <(E-Mail Removed)>
escribió:
> brooklineTom <(E-Mail Removed)> writes:
>
>> I want my exception handler to report the method that originally
>> raised an exception, at the deepest level in the call-tree. Let give
>> an example.


> extract_stack() without any arguments is getting this from the
> *current frame* which as you noted doesn't have the last exception
> info included which has been popped; variable sys.last_traceback has the
> frames
> at the time of the exception, I think.
>
> So in your code try changing:
> aRawStack = traceback.extract_stack()
> to
> aRawStack = traceback.extract_stack(sys.last_traceback)


No, last_traceback is the last *printed* traceback in the interactive
interpreter. Use the third element in sys.exc_info() instead:

import sys, traceback

class SomeClass:
def error(self):
"""Raises an AttributeError exception."""
int(3).zork()

def perform_(self, aSelector):
try:
aMethod = getattr(self, aSelector)
answer = aMethod()
except AttributeError:
tb = sys.exc_info()[2]
try:
print "Using traceback.print_tb:"
traceback.print_tb(tb)
print "Using traceback.print_exception:"
traceback.print_exception(*sys.exc_info())
print "Using traceback.extract_tb:"
print traceback.extract_tb(tb)
finally:
del tb

SomeClass().perform_("error")

output:

Using traceback.print_tb:
File "test_tb.py", line 11, in perform_
answer = aMethod()
File "test_tb.py", line 6, in error
int(3).zork()
Using traceback.print_exception:
Traceback (most recent call last):
File "test_tb.py", line 11, in perform_
answer = aMethod()
File "test_tb.py", line 6, in error
int(3).zork()
AttributeError: 'int' object has no attribute 'zork'
Using traceback.extract_tb:
[('test_tb.py', 11, 'perform_', 'answer = aMethod()'), ('test_tb.py', 6,
'error'
, 'int(3).zork()')]

(The "3-name form of the except clause" that I menctioned previously only
exists in my imagination )

--
Gabriel Genellina

 
Reply With Quote
 
R. Bernstein
Guest
Posts: n/a
 
      12-13-2008
"Gabriel Genellina" <(E-Mail Removed)> writes:
...

> No, last_traceback is the last *printed* traceback in the interactive
> interpreter.


Well more precisely the traceback that is passed to sys.excepthook()
when an unhandled exception occcurs, since the hook that might not
decide to print anything

> Use the third element in sys.exc_info() instead:


Hmm... I'm not sure what I was thinking when I read that way back
when, but you are correct and caught a bug in my code. I really do
need to do better about writing tests. Maybe next
incarnation... Thanks.
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
for language experts: Constants defined in an entity visible in all deeper inner entities albert.neu@gmail.com VHDL 7 05-09-2006 02:43 PM
how to parse deeper nested tags in custom control =?Utf-8?B?U0VC?= ASP .Net 2 11-26-2005 10:56 PM
We are getting deeper and deeper of ctype.h and isspace() ,but no one is telling me ths solution ! Durgesh Sharma C Programming 5 12-21-2004 07:35 AM
Beans and Bean builder deeper knowing. jenniferyiu Java 0 12-03-2003 12:50 PM
Beans and Bean builder deeper knowing. jenniferyiu Java 0 12-03-2003 12:48 PM



Advertisments