Get Only the Last Items in a Traceback

Discussion in 'Python' started by gregpinero@gmail.com, Sep 12, 2007.

  1. Guest

    I'm running code via the "exec in context" statement within a much
    larger program. What I would like to do is capture any possible
    errors and show a pretty traceback just like the Python interactive
    interpreter does, but only show the part of the traceback relating to
    the code sent to exec.

    For example here is the code I'm using:

    try:
    exec code
    except Exception,Err:
    traceback.print_exc()

    Which gives me something like this when it catches an exception:

    Traceback (most recent call last):
    File "/....py", line 843, in run
    semi_safe_exec.safe_eval(code.replace('\r',''),context,5)
    File ".....py", line 400, in safe_eval
    exec_timed(code, context, timeout_secs)
    File ".....py", line 353, in exec_timed
    exec code in context
    File "<string>", line 7, in ?
    File "<string>", line 5, in func2
    File "<string>", line 2, in func1
    ZeroDivisionError: integer division or modulo by zero

    What I want to print instead is just something like:

    Traceback (most recent call last):
    File "<string>", line 7, in ?
    File "<string>", line 5, in func2
    File "<string>", line 2, in func1
    ZeroDivisionError: integer division or modulo by zero

    Thanks in advance for the help.

    -Greg

    P.S. if it matters, for this example, code in exec code is:

    def func1():
    print 7/0

    def func2():
    func1()

    func2()
     
    , Sep 12, 2007
    #1
    1. Advertising

  2. Peter Otten Guest

    Am Wed, 12 Sep 2007 02:09:28 +0000 schrieb :

    > I'm running code via the "exec in context" statement within a much
    > larger program. What I would like to do is capture any possible
    > errors and show a pretty traceback just like the Python interactive
    > interpreter does, but only show the part of the traceback relating to
    > the code sent to exec.
    >
    > For example here is the code I'm using:
    >
    > try:
    > exec code
    > except Exception,Err:
    > traceback.print_exc()
    >
    > Which gives me something like this when it catches an exception:
    >
    > Traceback (most recent call last):
    > File "/....py", line 843, in run
    > semi_safe_exec.safe_eval(code.replace('\r',''),context,5)
    > File ".....py", line 400, in safe_eval
    > exec_timed(code, context, timeout_secs)
    > File ".....py", line 353, in exec_timed
    > exec code in context
    > File "<string>", line 7, in ?
    > File "<string>", line 5, in func2
    > File "<string>", line 2, in func1
    > ZeroDivisionError: integer division or modulo by zero
    >
    > What I want to print instead is just something like:
    >
    > Traceback (most recent call last):
    > File "<string>", line 7, in ?
    > File "<string>", line 5, in func2
    > File "<string>", line 2, in func1
    > ZeroDivisionError: integer division or modulo by zero
    >
    > Thanks in advance for the help.
    >
    > -Greg
    >
    > P.S. if it matters, for this example, code in exec code is:
    >
    > def func1():
    > print 7/0
    >
    > def func2():
    > func1()
    >
    > func2()


    Your assessment is wrong. You only get the extra lines in the traceback if
    you don't immediately wrap the exec statement in a try ... except block:

    $ cat snip_traceback1.py
    import traceback

    def alpha():
    try:
    beta()
    except Exception, e:
    traceback.print_exc()

    def beta():
    gamma()

    def gamma():
    exec s in {}

    s = """
    def delta():
    epsilon()

    def epsilon():
    1/0
    delta()
    """

    if __name__ == "__main__":
    alpha()

    $ python snip_traceback1.py
    Traceback (most recent call last):
    File "snip_traceback1.py", line 5, in alpha
    beta()
    File "snip_traceback1.py", line 10, in beta
    gamma()
    File "snip_traceback1.py", line 13, in gamma
    exec s in {}
    File "<string>", line 7, in <module>
    File "<string>", line 3, in delta
    File "<string>", line 6, in epsilon
    ZeroDivisionError: integer division or modulo by zero

    So the first step is to move the try ... except closer to the exec:

    $ cat snip_traceback2.py
    import traceback

    def alpha():
    beta()

    def beta():
    gamma()

    def gamma():
    try:
    exec s in {}
    except Exception, e:
    traceback.print_exc()

    s = """
    def delta():
    epsilon()

    def epsilon():
    1/0
    delta()
    """

    if __name__ == "__main__":
    alpha()

    $ python snip_traceback2.py
    Traceback (most recent call last):
    File "snip_traceback2.py", line 11, in gamma
    exec s in {}
    File "<string>", line 7, in <module>
    File "<string>", line 3, in delta
    File "<string>", line 6, in epsilon
    ZeroDivisionError: integer division or modulo by zero

    You are almost there. Now let's strip off the outermost traceback:

    $ cat snip_traceback3.py
    import sys
    import traceback

    def alpha():
    beta()

    def beta():
    gamma()

    def gamma():
    try:
    exec s in {}
    except Exception, e:
    etype, value, tb = sys.exc_info()
    traceback.print_exception(etype, value, tb.tb_next)

    s = """
    def delta():
    epsilon()

    def epsilon():
    1/0
    delta()
    """

    if __name__ == "__main__":
    alpha()

    $ python snip_traceback3.py
    Traceback (most recent call last):
    File "<string>", line 7, in <module>
    File "<string>", line 3, in delta
    File "<string>", line 6, in epsilon
    ZeroDivisionError: integer division or modulo by zero

    Heureka.

    Peter
     
    Peter Otten, Sep 12, 2007
    #2
    1. Advertising

  3. wrote:
    > I'm running code via the "exec in context" statement within a much
    > larger program. What I would like to do is capture any possible
    > errors and show a pretty traceback just like the Python interactive
    > interpreter does, but only show the part of the traceback relating to
    > the code sent to exec.
    >
    > For example here is the code I'm using:
    >
    > try:
    > exec code
    > except Exception,Err:
    > traceback.print_exc()


    Guess what's argument limit is for. Excerpt from the Python docs:

    -------------------------------- snip --------------------------------
    print_exc( [limit[, file]])
    This is a shorthand for print_exception(sys.exc_type, sys.exc_value,
    sys.exc_traceback, limit, file). (In fact, it uses sys.exc_info() to
    retrieve the same information in a thread-safe way instead of using the
    deprecated variables.)
    -------------------------------- snip --------------------------------

    Ciao, Michael.
     
    =?ISO-8859-1?Q?Michael_Str=F6der?=, Sep 12, 2007
    #3
  4. Peter Otten Guest

    Am Wed, 12 Sep 2007 11:21:48 +0200 schrieb Michael Ströder:

    > wrote:
    >> I'm running code via the "exec in context" statement within a much
    >> larger program. What I would like to do is capture any possible
    >> errors and show a pretty traceback just like the Python interactive
    >> interpreter does, but only show the part of the traceback relating to
    >> the code sent to exec.
    >>
    >> For example here is the code I'm using:
    >>
    >> try:
    >> exec code
    >> except Exception,Err:
    >> traceback.print_exc()

    >
    > Guess what's argument limit is for. Excerpt from the Python docs:


    Unfortunately traceback.print_exc(limit=N) trims the wrong end of the
    traceback:

    >>> def alpha(): beta()

    ....
    >>> def beta(): gamma()

    ....
    >>> def gamma(): 1/0

    ....
    >>> try:

    .... alpha()
    .... except:
    .... traceback.print_exc()
    ....
    Traceback (most recent call last):
    File "<stdin>", line 2, in <module>
    File "<stdin>", line 1, in alpha
    File "<stdin>", line 1, in beta
    File "<stdin>", line 1, in gamma
    ZeroDivisionError: integer division or modulo by zero
    >>> try:

    .... alpha()
    .... except:
    .... traceback.print_exc(limit=1)
    ....
    Traceback (most recent call last):
    File "<stdin>", line 2, in <module>
    ZeroDivisionError: integer division or modulo by zero
    >>>


    Peter
     
    Peter Otten, Sep 12, 2007
    #4
  5. Guest

    On Sep 12, 5:17 am, Peter Otten <> wrote:
    >
    > Your assessment is wrong. You only get the extra lines in the traceback if
    > you don't immediately wrap the exec statement in a try ... except block:
    >
    > $ cat snip_traceback1.py
    > import traceback
    >
    > def alpha():
    > try:
    > beta()
    > except Exception, e:
    > traceback.print_exc()
    >
    > def beta():
    > gamma()
    >
    > def gamma():
    > exec s in {}
    >
    > s = """
    > def delta():
    > epsilon()
    >
    > def epsilon():
    > 1/0
    > delta()
    > """
    >
    > if __name__ == "__main__":
    > alpha()
    >
    > $ python snip_traceback1.py
    > Traceback (most recent call last):
    > File "snip_traceback1.py", line 5, in alpha
    > beta()
    > File "snip_traceback1.py", line 10, in beta
    > gamma()
    > File "snip_traceback1.py", line 13, in gamma
    > exec s in {}
    > File "<string>", line 7, in <module>
    > File "<string>", line 3, in delta
    > File "<string>", line 6, in epsilon
    > ZeroDivisionError: integer division or modulo by zero
    >
    > So the first step is to move the try ... except closer to the exec:
    >
    > $ cat snip_traceback2.py
    > import traceback
    >
    > def alpha():
    > beta()
    >
    > def beta():
    > gamma()
    >
    > def gamma():
    > try:
    > exec s in {}
    > except Exception, e:
    > traceback.print_exc()
    >
    > s = """
    > def delta():
    > epsilon()
    >
    > def epsilon():
    > 1/0
    > delta()
    > """
    >
    > if __name__ == "__main__":
    > alpha()
    >
    > $ python snip_traceback2.py
    > Traceback (most recent call last):
    > File "snip_traceback2.py", line 11, in gamma
    > exec s in {}
    > File "<string>", line 7, in <module>
    > File "<string>", line 3, in delta
    > File "<string>", line 6, in epsilon
    > ZeroDivisionError: integer division or modulo by zero
    >
    > You are almost there. Now let's strip off the outermost traceback:
    >
    > $ cat snip_traceback3.py
    > import sys
    > import traceback
    >
    > def alpha():
    > beta()
    >
    > def beta():
    > gamma()
    >
    > def gamma():
    > try:
    > exec s in {}
    > except Exception, e:
    > etype, value, tb = sys.exc_info()
    > traceback.print_exception(etype, value, tb.tb_next)
    >
    > s = """
    > def delta():
    > epsilon()
    >
    > def epsilon():
    > 1/0
    > delta()
    > """
    >
    > if __name__ == "__main__":
    > alpha()
    >
    > $ python snip_traceback3.py
    > Traceback (most recent call last):
    > File "<string>", line 7, in <module>
    > File "<string>", line 3, in delta
    > File "<string>", line 6, in epsilon
    > ZeroDivisionError: integer division or modulo by zero
    >
    > Heureka.
    >
    > Peter


    Thanks for the help, Peter. That's exactly what I need. Now could I
    use your tb.tb_next trick a couple times and thus avoid moving the try/
    except?

    -Greg
     
    , Sep 12, 2007
    #5
  6. Peter Otten Guest

    Am Wed, 12 Sep 2007 15:09:02 +0000 schrieb :

    > On Sep 12, 5:17 am, Peter Otten <> wrote:
    >>
    >> Your assessment is wrong. You only get the extra lines in the traceback if
    >> you don't immediately wrap the exec statement in a try ... except block:


    >> $ cat snip_traceback3.py
    >> import sys
    >> import traceback
    >>
    >> def alpha():
    >> beta()
    >>
    >> def beta():
    >> gamma()
    >>
    >> def gamma():
    >> try:
    >> exec s in {}
    >> except Exception, e:
    >> etype, value, tb = sys.exc_info()
    >> traceback.print_exception(etype, value, tb.tb_next)
    >>
    >> s = """
    >> def delta():
    >> epsilon()
    >>
    >> def epsilon():
    >> 1/0
    >> delta()
    >> """
    >>
    >> if __name__ == "__main__":
    >> alpha()
    >>
    >> $ python snip_traceback3.py
    >> Traceback (most recent call last):
    >> File "<string>", line 7, in <module>
    >> File "<string>", line 3, in delta
    >> File "<string>", line 6, in epsilon
    >> ZeroDivisionError: integer division or modulo by zero
    >>
    >> Heureka.


    > Thanks for the help, Peter. That's exactly what I need.


    Indeed. But not exactly what you want, it seems.

    > Now could I
    > use your tb.tb_next trick a couple times and thus avoid moving the try/
    > except?


    Of course you can cut off the traceback at arbitrary positions. Here's an
    example that uses the filename:

    import traceback
    import sys

    def tb_filename(tb):
    return tb.tb_frame.f_code.co_filename

    def tb_iter(tb):
    while tb is not None:
    yield tb
    tb = tb.tb_next

    def alpha():
    try:
    beta()
    except Exception, e:
    etype, value, tb = sys.exc_info()
    filename = tb_filename(tb)
    for tb in tb_iter(tb):
    if tb_filename(tb) != filename:
    break
    traceback.print_exception(etype, value, tb)

    def beta():
    gamma()

    def gamma():
    exec s in {}

    s = """
    def delta():
    epsilon()

    def epsilon():
    1/0
    delta()
    """

    if __name__ == "__main__":
    alpha()

    Did I mention it already? It's better to move the try ... except.

    Peter
     
    Peter Otten, Sep 12, 2007
    #6
  7. Guest

    On Sep 12, 11:35 am, Peter Otten <> wrote:
    > Am Wed, 12 Sep 2007 15:09:02 +0000 schrieb :
    >
    >
    >
    > > On Sep 12, 5:17 am, Peter Otten <> wrote:

    >
    > >> Your assessment is wrong. You only get the extra lines in the traceback if
    > >> you don't immediately wrap the exec statement in a try ... except block:
    > >> $ cat snip_traceback3.py
    > >> import sys
    > >> import traceback

    >
    > >> def alpha():
    > >> beta()

    >
    > >> def beta():
    > >> gamma()

    >
    > >> def gamma():
    > >> try:
    > >> exec s in {}
    > >> except Exception, e:
    > >> etype, value, tb = sys.exc_info()
    > >> traceback.print_exception(etype, value, tb.tb_next)

    >
    > >> s = """
    > >> def delta():
    > >> epsilon()

    >
    > >> def epsilon():
    > >> 1/0
    > >> delta()
    > >> """

    >
    > >> if __name__ == "__main__":
    > >> alpha()

    >
    > >> $ python snip_traceback3.py
    > >> Traceback (most recent call last):
    > >> File "<string>", line 7, in <module>
    > >> File "<string>", line 3, in delta
    > >> File "<string>", line 6, in epsilon
    > >> ZeroDivisionError: integer division or modulo by zero

    >
    > >> Heureka.

    > > Thanks for the help, Peter. That's exactly what I need.

    >
    > Indeed. But not exactly what you want, it seems.
    >
    > > Now could I
    > > use your tb.tb_next trick a couple times and thus avoid moving the try/
    > > except?

    >
    > Of course you can cut off the traceback at arbitrary positions. Here's an
    > example that uses the filename:
    >
    > import traceback
    > import sys
    >
    > def tb_filename(tb):
    > return tb.tb_frame.f_code.co_filename
    >
    > def tb_iter(tb):
    > while tb is not None:
    > yield tb
    > tb = tb.tb_next
    >
    > def alpha():
    > try:
    > beta()
    > except Exception, e:
    > etype, value, tb = sys.exc_info()
    > filename = tb_filename(tb)
    > for tb in tb_iter(tb):
    > if tb_filename(tb) != filename:
    > break
    > traceback.print_exception(etype, value, tb)
    >
    > def beta():
    > gamma()
    >
    > def gamma():
    > exec s in {}
    >
    > s = """
    > def delta():
    > epsilon()
    >
    > def epsilon():
    > 1/0
    > delta()
    > """
    >
    > if __name__ == "__main__":
    > alpha()
    >
    > Did I mention it already? It's better to move the try ... except.
    >
    > Peter



    This approach is ideal. Indirect, but ideal :) I'll apply it
    tonight.

    It's complicated but suffice it to say it would be difficult to move
    the try/except. Thanks for the help. Way to know about tracebacks,
    very impressive!

    -Greg
     
    , Sep 12, 2007
    #7
  8. Guest

    On Sep 12, 10:35 am, Peter Otten <> wrote:
    > Am Wed, 12 Sep 2007 15:09:02 +0000 schrieb :
    >
    > > On Sep 12, 5:17 am, Peter Otten <> wrote:

    >
    > >> Your assessment is wrong. You only get the extra lines in the traceback if
    > >> you don't immediately wrap the exec statement in a try ... except block:
    > >> $ cat snip_traceback3.py
    > >> import sys
    > >> import traceback

    >
    > >> def alpha():
    > >> beta()

    >
    > >> def beta():
    > >> gamma()

    >
    > >> def gamma():
    > >> try:
    > >> exec s in {}
    > >> except Exception, e:
    > >> etype, value, tb = sys.exc_info()
    > >> traceback.print_exception(etype, value, tb.tb_next)

    >
    > >> s = """
    > >> def delta():
    > >> epsilon()

    >
    > >> def epsilon():
    > >> 1/0
    > >> delta()
    > >> """

    >
    > >> if __name__ == "__main__":
    > >> alpha()

    >
    > >> $ python snip_traceback3.py
    > >> Traceback (most recent call last):
    > >> File "<string>", line 7, in <module>
    > >> File "<string>", line 3, in delta
    > >> File "<string>", line 6, in epsilon
    > >> ZeroDivisionError: integer division or modulo by zero

    >
    > >> Heureka.

    > > Thanks for the help, Peter. That's exactly what I need.

    >
    > Indeed. But not exactly what you want, it seems.
    >
    > > Now could I
    > > use your tb.tb_next trick a couple times and thus avoid moving the try/
    > > except?

    >
    > Of course you can cut off the traceback at arbitrary positions. Here's an
    > example that uses the filename:
    >
    > import traceback
    > import sys
    >
    > def tb_filename(tb):
    > return tb.tb_frame.f_code.co_filename
    >
    > def tb_iter(tb):
    > while tb is not None:
    > yield tb
    > tb = tb.tb_next
    >
    > def alpha():
    > try:
    > beta()
    > except Exception, e:
    > etype, value, tb = sys.exc_info()
    > filename = tb_filename(tb)
    > for tb in tb_iter(tb):
    > if tb_filename(tb) != filename:
    > break
    > traceback.print_exception(etype, value, tb)
    >
    > def beta():
    > gamma()
    >
    > def gamma():
    > exec s in {}
    >
    > s = """
    > def delta():
    > epsilon()
    >
    > def epsilon():
    > 1/0
    > delta()
    > """
    >
    > if __name__ == "__main__":
    > alpha()
    >
    > Did I mention it already? It's better to move the try ... except.
    >
    > Peter


    This works great except for syntax errors. Any idea why your solution
    doesn't catch those?

    Here's the output it gives me, followed by the code I'm using (running
    in Python 2.5):

    Traceback (most recent call last):
    File "traceback_test.py", line 27, in gamma
    exec s in {}
    File "<string>", line 6
    print hi'
    ^
    SyntaxError: EOL while scanning single-quoted string


    file traceback_test.py contents:
    import traceback
    import sys

    def tb_filename(tb):
    return tb.tb_frame.f_code.co_filename

    def tb_iter(tb):
    while tb is not None:
    yield tb
    tb = tb.tb_next

    def alpha():
    try:
    beta()
    except Exception, e:
    etype, value, tb = sys.exc_info()
    filename = tb_filename(tb)
    for tb in tb_iter(tb):
    if tb_filename(tb) != filename:
    break
    traceback.print_exception(etype, value, tb)

    def beta():
    gamma()

    def gamma():
    exec s in {}

    s = """
    def delta():
    epsilon()

    def epsilon():
    print hi'
    delta()
    """

    if __name__ == "__main__":
    alpha()

    -Greg
     
    , Nov 7, 2007
    #8
  9. En Wed, 07 Nov 2007 01:53:31 -0300,
    <> escribió:

    > This works great except for syntax errors. Any idea why your solution
    > doesn't catch those?
    >
    > Here's the output it gives me, followed by the code I'm using (running
    > in Python 2.5):
    >
    > Traceback (most recent call last):
    > File "traceback_test.py", line 27, in gamma
    > exec s in {}
    > File "<string>", line 6
    > print hi'
    > ^
    > SyntaxError: EOL while scanning single-quoted string


    Which would be your expected output?
    Syntax errors happen when the code is *compiled*, before it gets executed.
    You may catch syntax errors before even trying to execute the code, if you
    do it in two steps:

    try:
    ccode = compile(s, filename, 'exec')
    except SyntaxError:
    ...show the error appropiately...
    ...abort execution...
    try:
    exec ccode in {}
    except Exception, e:
    ...handle exception...


    --
    Gabriel Genellina
     
    Gabriel Genellina, Nov 10, 2007
    #9
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. sangram
    Replies:
    16
    Views:
    2,062
  2. Replies:
    1
    Views:
    845
    Peter Otten
    Oct 12, 2007
  3. Replies:
    0
    Views:
    347
  4. Gabriel Genellina
    Replies:
    4
    Views:
    11,155
    JodyGnumeric
    Dec 10, 2008
  5. Jack Bates
    Replies:
    0
    Views:
    289
    Jack Bates
    May 2, 2011
Loading...

Share This Page