Get exception description and stack trace which caused an exception, all as a string

前端 未结 11 1796
旧巷少年郎
旧巷少年郎 2020-11-30 16:22

I\'ve seen a lot of posts about stack trace and exceptions in Python. But haven\'t found what I need.

I have a chunk of Python 2.7 code that may raise an exception.

相关标签:
11条回答
  • 2020-11-30 16:38

    my 2-cents:

    import sys, traceback
    try: 
      ...
    except Exception, e:
      T, V, TB = sys.exc_info()
      print ''.join(traceback.format_exception(T,V,TB))
    
    0 讨论(0)
  • 2020-11-30 16:39

    With Python 3, the following code will format an Exception object exactly as would be obtained using traceback.format_exc():

    import traceback
    
    try: 
        method_that_can_raise_an_exception(params)
    except Exception as ex:
        print(''.join(traceback.format_exception(etype=type(ex), value=ex, tb=ex.__traceback__)))
    

    The advantage being that only the Exception object is needed (thanks to the recorded __traceback__ attribute), and can therefore be more easily passed as an argument to another function for further processing.

    0 讨论(0)
  • 2020-11-30 16:40

    For Python 3.5+:

    So, you can get the stacktrace from your exception as from any other exception. Use traceback.TracebackException for it (just replace ex with your exception):

    print("".join(traceback.TracebackException.from_exception(ex).format())
    

    An extended example and other features to do this:

    import traceback
    
    try:
        1/0
    except Exception as ex:
        print("".join(traceback.TracebackException.from_exception(ex).format()) == traceback.format_exc() == "".join(traceback.format_exception(type(ex), ex, ex.__traceback__))) # This is True !!
        print("".join(traceback.TracebackException.from_exception(ex).format()))
    

    The output will be something like this:

    True
    Traceback (most recent call last):
      File "untidsfsdfsdftled.py", line 29, in <module>
        1/0
    ZeroDivisionError: division by zero
    
    0 讨论(0)
  • 2020-11-30 16:41

    You might also consider using the built-in Python module, cgitb, to get some really good, nicely formatted exception information including local variable values, source code context, function parameters etc..

    For instance for this code...

    import cgitb
    cgitb.enable(format='text')
    
    def func2(a, divisor):
        return a / divisor
    
    def func1(a, b):
        c = b - 5
        return func2(a, c)
    
    func1(1, 5)
    

    we get this exception output...

    ZeroDivisionError
    Python 3.4.2: C:\tools\python\python.exe
    Tue Sep 22 15:29:33 2015
    
    A problem occurred in a Python script.  Here is the sequence of
    function calls leading up to the error, in the order they occurred.
    
     c:\TEMP\cgittest2.py in <module>()
        7 def func1(a, b):
        8   c = b - 5
        9   return func2(a, c)
       10
       11 func1(1, 5)
    func1 = <function func1>
    
     c:\TEMP\cgittest2.py in func1(a=1, b=5)
        7 def func1(a, b):
        8   c = b - 5
        9   return func2(a, c)
       10
       11 func1(1, 5)
    global func2 = <function func2>
    a = 1
    c = 0
    
     c:\TEMP\cgittest2.py in func2(a=1, divisor=0)
        3
        4 def func2(a, divisor):
        5   return a / divisor
        6
        7 def func1(a, b):
    a = 1
    divisor = 0
    ZeroDivisionError: division by zero
        __cause__ = None
        __class__ = <class 'ZeroDivisionError'>
        __context__ = None
        __delattr__ = <method-wrapper '__delattr__' of ZeroDivisionError object>
        __dict__ = {}
        __dir__ = <built-in method __dir__ of ZeroDivisionError object>
        __doc__ = 'Second argument to a division or modulo operation was zero.'
        __eq__ = <method-wrapper '__eq__' of ZeroDivisionError object>
        __format__ = <built-in method __format__ of ZeroDivisionError object>
        __ge__ = <method-wrapper '__ge__' of ZeroDivisionError object>
        __getattribute__ = <method-wrapper '__getattribute__' of ZeroDivisionError object>
        __gt__ = <method-wrapper '__gt__' of ZeroDivisionError object>
        __hash__ = <method-wrapper '__hash__' of ZeroDivisionError object>
        __init__ = <method-wrapper '__init__' of ZeroDivisionError object>
        __le__ = <method-wrapper '__le__' of ZeroDivisionError object>
        __lt__ = <method-wrapper '__lt__' of ZeroDivisionError object>
        __ne__ = <method-wrapper '__ne__' of ZeroDivisionError object>
        __new__ = <built-in method __new__ of type object>
        __reduce__ = <built-in method __reduce__ of ZeroDivisionError object>
        __reduce_ex__ = <built-in method __reduce_ex__ of ZeroDivisionError object>
        __repr__ = <method-wrapper '__repr__' of ZeroDivisionError object>
        __setattr__ = <method-wrapper '__setattr__' of ZeroDivisionError object>
        __setstate__ = <built-in method __setstate__ of ZeroDivisionError object>
        __sizeof__ = <built-in method __sizeof__ of ZeroDivisionError object>
        __str__ = <method-wrapper '__str__' of ZeroDivisionError object>
        __subclasshook__ = <built-in method __subclasshook__ of type object>
        __suppress_context__ = False
        __traceback__ = <traceback object>
        args = ('division by zero',)
        with_traceback = <built-in method with_traceback of ZeroDivisionError object>
    
    The above is a description of an error in a Python program.  Here is
    the original traceback:
    
    Traceback (most recent call last):
      File "cgittest2.py", line 11, in <module>
        func1(1, 5)
      File "cgittest2.py", line 9, in func1
        return func2(a, c)
      File "cgittest2.py", line 5, in func2
        return a / divisor
    ZeroDivisionError: division by zero
    
    0 讨论(0)
  • 2020-11-30 16:45

    For those using Python-3

    Using traceback module and exception.__traceback__ one can extract the stack-trace as follows:

    • grab the current stack-trace using traceback.extract_stack()
    • remove the last three elements (as those are entries in the stack that got me to my debug function)
    • append the __traceback__ from the exception object using traceback.extract_tb()
    • format the whole thing using traceback.format_list()
    import traceback
    def exception_to_string(excp):
       stack = traceback.extract_stack()[:-3] + traceback.extract_tb(excp.__traceback__)  # add limit=?? 
       pretty = traceback.format_list(stack)
       return ''.join(pretty) + '\n  {} {}'.format(excp.__class__,excp)
    

    A simple demonstration:

    def foo():
        try:
            something_invalid()
        except Exception as e:
            print(exception_to_string(e))
    
    def bar():
        return foo()
    

    We get the following output when we call bar():

      File "./test.py", line 57, in <module>
        bar()
      File "./test.py", line 55, in bar
        return foo()
      File "./test.py", line 50, in foo
        something_invalid()
    
      <class 'NameError'> name 'something_invalid' is not defined
    
    0 讨论(0)
  • 2020-11-30 16:45

    If your goal is to make the exception and stacktrace message look exactly like when python throws an error, the following works in both python 2+3:

    import sys, traceback
    
    
    def format_stacktrace():
        parts = ["Traceback (most recent call last):\n"]
        parts.extend(traceback.format_stack(limit=25)[:-2])
        parts.extend(traceback.format_exception(*sys.exc_info())[1:])
        return "".join(parts)
    
    # EXAMPLE BELOW...
    
    def a():
        b()
    
    
    def b():
        c()
    
    
    def c():
        d()
    
    
    def d():
        assert False, "Noooh don't do it."
    
    
    print("THIS IS THE FORMATTED STRING")
    print("============================\n")
    
    try:
        a()
    except:
        stacktrace = format_stacktrace()
        print(stacktrace)
    
    print("THIS IS HOW PYTHON DOES IT")
    print("==========================\n")
    a()
    

    It works by removing the last format_stacktrace() call from the stack and joining the rest. When run, the example above gives the following output:

    THIS IS THE FORMATTED STRING
    ============================
    
    Traceback (most recent call last):
      File "test.py", line 31, in <module>
        a()
      File "test.py", line 12, in a
        b()
      File "test.py", line 16, in b
        c()
      File "test.py", line 20, in c
        d()
      File "test.py", line 24, in d
        assert False, "Noooh don't do it."
    AssertionError: Noooh don't do it.
    
    THIS IS HOW PYTHON DOES IT
    ==========================
    
    Traceback (most recent call last):
      File "test.py", line 38, in <module>
        a()
      File "test.py", line 12, in a
        b()
      File "test.py", line 16, in b
        c()
      File "test.py", line 20, in c
        d()
      File "test.py", line 24, in d
        assert False, "Noooh don't do it."
    AssertionError: Noooh don't do it.
    
    0 讨论(0)
提交回复
热议问题