[Tutor] traceback -- how it works?

spir denis.spir at free.fr
Thu Jan 15 14:19:22 CET 2009


Le Wed, 14 Jan 2009 21:19:11 +0100,
Willi Richert <w.richert at gmx.net> a écrit :

> Hi,
> 
> do you observe the same behavior with traceback.format_exc()? I've used that 
> always in such situations which worked all the time.
> 
> Regards,
> wr

Hello again, Willi & all,

I guess I got the point. I thought that tracebacks where generated when an exception occurs, and
then the exception itself was in a way linked to the matching traceback. Actually I thought that
because the trace path exists before the exception. But I was wrong. It seems instead that the
exception is first generated and only a traceback object. Maybe python generates the traceback
only when it needs to print out the exception report, a part of which beeing the traceback.
As a consequence, when an exception is created, no traceback exists at all, so that it may not be
possible to have custom exceptions know about their own tracbacks.

I wanted for a trial to have an "Error" type print out traceback in a different form. With
rather complicated tests using a project of mine, I got what seemed unpredictable results where
sometimes only a traceback existed.
But simply launching an Error gives this:

raise Error("TEST")
==>
Traceback (most recent call last):
  File "tools.py", line 324, in <module>
    testError()
  File "tools.py", line 287, in testError
    raise Error("TEST")
__main__.Error: 
<no error trace>
TEST

Now, if I catch the first exception by nesting it inside a try...except, I will get the traceback
of the first exception inside the second one:

try:
	print 1/0
except ZeroDivisionError,error:
	raise Error(str(error) + " -- CAUGHT")
==>
Traceback (most recent call last):
  File "tools.py", line 324, in <module>
    testError()
  File "tools.py", line 291, in testError
    raise Error(str(error) + " -- CAUGHT")
__main__.Error: 
<error trace>
   module 'tools.py'-- in testError():
      line 00289:  print 1/0
integer division or modulo by zero -- CAUGHT

Another more complex test involving an exception generated from within en external module gives:

### module tools.py ###
from throw_error import throw_error
def raise_uncaught_error():
	try:
		throw_error()
	except TypeError:
		raise Error("A set cannot hold a mutable item.")
### module throw_error.py ###
from sets import Set
def build_set(l):
	s = Set(l)
def throw_error():
	build_set([[1,2,3]])
==>
Traceback (most recent call last):
  File "tools.py", line 318, in <module>
    testError()
  File "tools.py", line 310, in testError
    raise_uncaught_error()
  File "tools.py", line 294, in raise_uncaught_error
    raise Error("A set cannot hold a mutable item.")
__main__.Error: 
<error trace>
   module 'tools.py'-- in raise_uncaught_error():
      line 00291:  throw_error()
   module '/home/spir/prog/ospyp/throw_error.py'-- in throw_error():
      line 00009:  build_set([[1,2,3]])
   module '/home/spir/prog/ospyp/throw_error.py'-- in build_set():
      line 00006:  s = Set(l)
   module '/usr/lib/python2.5/sets.py'-- in __init__():
      line 00429:  self._update(iterable)
   module '/usr/lib/python2.5/sets.py'-- in _update():
      line 00374:  data[element] = value
A set cannot hold a mutable item.

The python traceback is the one of the second exception (mine), while the traceback read and
reformatted by my custom exception is the one of the original exception (lauched by the module
sets). Which is rather interesting -- even if not what I intended to do.
Now, I can catch my own exception to avoid stopping a test unit run, for instance, and only print
out the exception message:

def raise_caught_error():
	try:
		raise_uncaught_error()
	except Error,error:
		print error
==>
<error trace>
   module 'tools.py'-- in raise_uncaught_error():
      line 00291:  throw_error()
   module '/home/spir/prog/ospyp/throw_error.py'-- in throw_error():
      line 00009:  build_set([[1,2,3]])
   module '/home/spir/prog/ospyp/throw_error.py'-- in build_set():
      line 00006:  s = Set(l)
   module '/usr/lib/python2.5/sets.py'-- in __init__():
      line 00429:  self._update(iterable)
   module '/usr/lib/python2.5/sets.py'-- in _update():
      line 00374:  data[element] = value
A set cannot hold a mutable item.

thank you for your help,
Denis

> Am Mittwoch, 14. Januar 2009 18:09:51 schrieb spir:
> > Hello,
> >
> > I rather often use exceptions as information providers at design or debug
> > time. A typical use of mine is to have a test version of methods that wrap
> > standard version:
> >
> > def run():
> > 	do stuff
> > 	that may
> > 	raise exc
> > def testRun():
> >  	try:
> > 		run()
> > 	except Error,error:
> > 		sys.error.write(str(error))
> >
> > So that I can run a bunch of (possibly failing) tests and still get all
> > worthful info. Now, the drawback is that I then lose python provided
> > traceback, as for any reason str(exc) does not return tracback, only the
> > "message". To have the traceback I planned to catch the traceback manually.
> > The aims whare:
> > * be able to output the tracback prepended to the message, when useful
> > * try to find a more readable (for me) format
> > * filter it: e.g. print only last trace mark of each module
> > If you have ideas on the best way to do this, thanks.
> >
> > I tried to use sys.exc_info() that returns a (type,value,traceback) tuple
> > and the format_tb() function of the traceback module. *Sometimes* I get the
> > traceback as expected and all is fine. But in most cases sys.exc_info()
> > returns (None,None,None) like if there was absolutely no active exception.
> > I cannot consistently reproduce the issue to make a clear diagnosis.
> >
> > Thank you,
> > Denis
> >

------
la vida e estranya


More information about the Tutor mailing list