Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: eliminating stack traces into library code?

Tags:

python

When I get a runtime exception from the standard library, it's almost always a problem in my code and not in the library code. Is there a way to truncate the exception stack trace so that it doesn't show the guts of the library package?

For example, I would like to get this:

Traceback (most recent call last):
  File "./lmd3-mkhead.py", line 71, in <module>
    main()
  File "./lmd3-mkhead.py", line 66, in main
    create()
  File "./lmd3-mkhead.py", line 41, in create
    headver1[depotFile]=rev
TypeError: Data values must be of type string or None.

and not this:

Traceback (most recent call last):
  File "./lmd3-mkhead.py", line 71, in <module>
    main()
  File "./lmd3-mkhead.py", line 66, in main
    create()
  File "./lmd3-mkhead.py", line 41, in create
    headver1[depotFile]=rev
  File "/usr/anim/modsquad/oses/fc11/lib/python2.6/bsddb/__init__.py", line 276, in __setitem__
    _DeadlockWrap(wrapF)  # self.db[key] = value
  File "/usr/anim/modsquad/oses/fc11/lib/python2.6/bsddb/dbutils.py", line 68, in DeadlockWrap
    return function(*_args, **_kwargs)
  File "/usr/anim/modsquad/oses/fc11/lib/python2.6/bsddb/__init__.py", line 275, in wrapF
    self.db[key] = value
TypeError: Data values must be of type string or None.

update: added an answer with the code, thanks to the pointer from Alex.

like image 901
Mark Harrison Avatar asked Apr 10 '10 23:04

Mark Harrison


People also ask

How do you not show traceback in Python?

The easiest way to configure these is using the jupyter_nbextensions_configurator serverextension, but you can also configure them directly with a few lines of python. The available options are: skip-traceback. animation_duration - duration (in milliseconds) of the show/hide traceback animations.

How do you get a stack trace for each thread in a running Python script?

Inspect running process with pyrasite Find the process ID for the stuck Python process and run pyrasite-shell with it. You should now see a Python REPL. Run the following in the REPL to see stack traces for all threads.

How do I print a stack trace in Python except?

Method 1: By using print_exc() method. This method prints exception information and stack trace entries from traceback object tb to file.

What is traceback library in Python?

Traceback is a python module that provides a standard interface to extract, format and print stack traces of a python program. When it prints the stack trace it exactly mimics the behaviour of a python interpreter.


2 Answers

The traceback module in Python's standard library lets you emit error tracebacks in a way that accords to your liking, while an exception is propagating. You can use this power either in the except leg of a try/except statement, or in a function you've installed as sys.excepthook, which gets called if and when an exception propagates all the way; quoting the docs:

In an interactive session this happens just before control is returned to the prompt; in a Python program this happens just before the program exits. The handling of such top-level exceptions can be customized by assigning another three-argument function to sys.excepthook.

Here's a simple, artificial example:

>>> import sys
>>> import traceback
>>> def f(n):
...   if n<=0: raise ZeroDivisionError
...   f(n-1)
... 
>>> def excepthook(type, value, tb):
...   traceback.print_exception(type, value, tb, 3)
... 
>>> sys.excepthook = excepthook
>>> f(8)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in f
  File "<stdin>", line 3, in f
ZeroDivisionError

as you see, without needing a try/except, you can easily limit the traceback to (for example) the first three levels -- even though we know by design that there were 9 nested levels when the exception was raised.

You want something more sophisticated than a simple limit on levels, so you'll need to call traceback.format_exception, which gives you a list of lines rather than printing it, then "prune" from that list the lines that are about modules you never want to see in your tracebacks, and finally emit the remaining lines (typically to sys.stderr, but, whatever!-).

like image 122
Alex Martelli Avatar answered Oct 22 '22 14:10

Alex Martelli


Thanks to the pointer from Alex, here's teh codez:

def trimmedexceptions(type, value, tb, pylibdir=None, lev=None):
    """trim system packages from the exception printout"""
    if pylibdir is None:
        import traceback, distutils.sysconfig
        pylibdir = distutils.sysconfig.get_python_lib(1,1)
        nlev = trimmedexceptions(type, value, tb, pylibdir, 0)
        traceback.print_exception(type, value, tb, nlev)
    else:
        fn = tb.tb_frame.f_code.co_filename
        if tb.tb_next is None or fn.startswith(pylibdir):
            return lev
        else:
            return trimmedexceptions(type, value, tb.tb_next, pylibdir, lev+1)

import sys
sys.excepthook=trimmedexceptions

# --- test code ---

def f1(): f2()
def f2(): f3()
def f3():
    import xmlrpclib
    proxy = xmlrpclib.ServerProxy('http://nosuchserver')
    proxy.f()

f1()

Which yields this stack trace:

Traceback (most recent call last):
  File "./tsttraceback.py", line 47, in <module>
    f1()
  File "./tsttraceback.py", line 40, in f1
    def f1(): f2()
  File "./tsttraceback.py", line 41, in f2
    def f2(): f3()
  File "./tsttraceback.py", line 45, in f3
    proxy.f()
gaierror: [Errno -2] Name or service not known
like image 40
Mark Harrison Avatar answered Oct 22 '22 15:10

Mark Harrison