如何将捕获的异常(其描述和堆栈跟踪)转换为外部使用的str ?

try:
    method_that_can_raise_an_exception(params)
except Exception as e:
    print(complete_exception_description(e))

当前回答

如果您希望在未处理异常时获得相同的信息,可以这样做。执行import trace,然后:

try:
    ...
except Exception as e:
    print(traceback.print_tb(e.__traceback__))

我使用的是Python 3.7。

其他回答

如果你想将你的回溯转换为dict的列表(适用于python > 3.5):

from traceback import TracebackException


def list_traceback(exc_value: BaseException):
    result = list()

    # get previous fails, so errors are appended by order of execution
    if exc_value.__context__:
        result += list_traceback(exc_value.__context__)

    # convert Exception into TracebackException
    tbe = TracebackException.from_exception(exc_value)

    # get stacktrace (cascade methods calls)
    error_lines = list()
    for frame_summary in tbe.stack:
        summary_details = {
            'filename': frame_summary.filename,
            'method'  : frame_summary.name,
            'lineno'  : frame_summary.lineno,
            'code'    : frame_summary.line
        }
        error_lines.append(summary_details)

    # append error, by order of execution
    result.append({"error_lines": error_lines,
                   "type"       : tbe.exc_type.__name__,
                   "message"    : str(tbe)})

    return result

这将是结果(一个例子):

[
   {
      "error_lines": [
         {
            "filename": "/home/demo/file2.py",
            "method": "do_error_2",
            "lineno": 18,
            "code": "a=1/0"
         }
      ],
      "type": "ZeroDivisionError",
      "message": "division by zero"
   },
   {
      "error_lines": [
         {
            "filename": "/home/demo/file_main.py",
            "method": "demo2",
            "lineno": 50,
            "code": "file2.DEMO().do_error_2()"
         },
         {
            "filename": "/home/demo/file2.py",
            "method": "do_error_2",
            "lineno": 20,
            "code": "raise AssertionError(\"Raised inside the except, after division by zero\")"
         }
      ],
      "type": "AssertionError",
      "message": "Raised inside the except, after division by zero"
   }
]
>>> import sys
>>> import traceback
>>> try:
...   5 / 0
... except ZeroDivisionError as e:
...   type_, value_, traceback_ = sys.exc_info()
>>> traceback.format_tb(traceback_)
['  File "<stdin>", line 2, in <module>\n']
>>> value_
ZeroDivisionError('integer division or modulo by zero',)
>>> type_
<type 'exceptions.ZeroDivisionError'>
>>>
>>> 5 / 0
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero

您可以使用sys.exc_info()收集信息,并使用traceback模块中的函数对其进行格式化。 下面是一些格式化的例子。

整个异常字符串位于:

>>> ex = traceback.format_exception(type_, value_, traceback_)
>>> ex
['Traceback (most recent call last):\n', '  File "<stdin>", line 2, in <module>\n', 'ZeroDivisionError: integer division or modulo by zero\n']

我定义了以下helper类:

import traceback
class TracedExeptions(object):
    def __init__(self):
        pass
    def __enter__(self):
        pass

    def __exit__(self, etype, value, tb):
      if value :
        if not hasattr(value, 'traceString'):
          value.traceString = "\n".join(traceback.format_exception(etype, value, tb))
        return False
      return True

我以后可以这样使用:

with TracedExeptions():
  #some-code-which-might-throw-any-exception

之后可以像这样消耗它:

def log_err(ex):
  if hasattr(ex, 'traceString'):
    print("ERROR:{}".format(ex.traceString));
  else:
    print("ERROR:{}".format(ex));

(背景:我很沮丧,因为使用承诺和异常一起,不幸的是将异常在一个地方引发到另一个地方的on_rejected处理程序,因此很难从原始位置获得回溯)

对于使用Python-3的用户

使用回溯模块和异常。__traceback__可以提取堆栈跟踪,如下所示:

使用traceback.extract_stack()获取当前堆栈跟踪 删除最后三个元素(因为它们是堆栈中的条目,使我找到了调试函数) 使用traceback.extract_tb()从异常对象中追加__traceback__ 使用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)

一个简单的演示:

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

def bar():
    return foo()

当我们调用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

对于Python 3.5+ 使用回溯。TracebackException,它可以处理在任何地方捕获的异常。

def print_trace(ex: BaseException):
    print(''.join(traceback.TracebackException.from_exception(ex).format()))

例子

import traceback

try:
    1/0
except Exception as ex:
    print(''.join(traceback.TracebackException.from_exception(ex).format()))

> >输出

Traceback (most recent call last):
  File "your_file_name_here.py", line 29, in <module>
    1/0
ZeroDivisionError: division by zero

它与from_exec()和format_exception()相同:

    a = ''.join(traceback.TracebackException.from_exception(ex).format())
    b = traceback.format_exc()
    c = ''.join(traceback.format_exception(type(ex), ex, ex.__traceback__))
    print(a == b == c)  # This is True !!