This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

Author ncoghlan
Recipients ggenellina, guettli, hoffman, ncoghlan, news1234, pakal, r.david.murray, vinay.sajip, ysj.ray
Date 2010-11-16.11:38:05
SpamBayes Score 3.03295e-11
Marked as misclassified No
Message-id <1289907487.31.0.369365670625.issue1553375@psf.upfronthosting.co.za>
In-reply-to
Content
Note that my suggestion was to move the if statement out of the loop as-is: you would still be pulling the traceback to display from the caught exception rather than displaying the stack from the current point of execution. If you want the bottom most point to display where the actual exception occurred rather than the last line executed in the frame that caught it you need to be even smarter than that, though.

The information to construct the full stack trace properly is actually available, but it is necessary to be very careful as to how it is stitched together at the point where the traceback and the stack trace meet up.

For a full stack trace, this stitching actually needs to occur every time there is a jump from one exception to another. For finally clauses and reraised exceptions, the interpreter handles this internally so the traceback reflects the appropriate lines, but recreating a complete stack trace for the original exception in the face of PEP 3134 is going to require a bit of work in the traceback module.

Alternatively, you could just provide the full stack trace for the very last exception caught, leaving it to the reader to follow the traceback chain back down to the original exception.

Here's some useful code to explore this (I just spent some time playing with it to make sure I was giving the right answer here):

import sys
from traceback import print_exc, print_stack, print_tb
def f(n):
  this = "F%d" % n
  if n:
    try:
      f(n-1)
    except:
      print("*** Traceback in", this)
      print_exc(chain=False)
      print("*** Call stack in", this)
      print_stack()
      print("*** Replacing exception in", this)
      raise RuntimeError(this)
  print("*** Call stack in", this)
  print_stack()
  raise RuntimeError(this)

try:
  f(2)
except:
  etype, ex, tb = sys.exc_info()

"raise ex" will then show you the native display of that exception.

You can then use the context attributes to see what state is available to you:
>>> ex
RuntimeError('F2',)
>>> ex.__context__
RuntimeError('F1',)
>>> ex.__context__.__context__
RuntimeError('F0',)

In particular, we can see that the two inner exceptions are attached to frame objects which were used to run the nested function calls and hence have a frame that called them:
>>> ex.__traceback__.tb_frame.f_back
>>> ex.__context__.__traceback__.tb_frame.f_back
<frame object at 0x2118ff0>
>>> ex.__context__.__context__.__traceback__.tb_frame.f_back
<frame object at 0x2115b80>

The issue we have is that landing in the exception handlers means the state of those frames has been altered by the stack unwinding process. Let's compare the traceback for each exception with the current state of the corresponding frame (we skip the first traceback entry for our outermost function - it is there courtesy of the interactive loop and irrelevant to the current exploration):

>>> ex.__traceback__.tb_next.tb_lineno # Top level exception line
2
>>> ex.__traceback__.tb_next.tb_frame.f_lineno # Last executed line
4
>>> ex.__context__.__traceback__.tb_lineno # f(2) exception line
5
>>> ex.__context__.__traceback__.tb_frame.f_lineno # Last executed line
12
>>> ex.__context__.__context__.__traceback__.tb_lineno # f(1) exception line
5
>>> ex.__context__.__context__.__traceback__.tb_frame.f_lineno # Last executed line
12

f(0) avoids triggering the exception handler and we can see that the traceback line and the last executed line match in that case:

>>> ex.__context__.__context__.__traceback__.tb_next.tb_lineno
15
>>> ex.__context__.__context__.__traceback__.tb_next.tb_frame.f_lineno
15

So yes, the idea proposed is possible, but no, a simple call to print_stack isn't going to do the right thing.
History
Date User Action Args
2010-11-16 11:38:07ncoghlansetrecipients: + ncoghlan, vinay.sajip, guettli, hoffman, ggenellina, pakal, r.david.murray, news1234, ysj.ray
2010-11-16 11:38:07ncoghlansetmessageid: <1289907487.31.0.369365670625.issue1553375@psf.upfronthosting.co.za>
2010-11-16 11:38:05ncoghlanlinkissue1553375 messages
2010-11-16 11:38:05ncoghlancreate