正如其他人建议的那样,您可以使用sys.excepthook:
此函数将给定的回溯和异常打印到 sys.stderr。
当异常被引发但未被捕获时,解释器调用 sys.excepthook 并带有三个参数,异常类、异常实例和回溯对象。在交互式会话中,这发生在控制返回到提示之前;在 Python 程序中,这发生在程序退出之前。 可以通过将另一个三参数函数分配给 sys.excepthook 来自定义对此类顶级异常的处理。
(强调我的)
可以根据指定目录过滤extract_tb(或traceback模块中的类似函数)提取的回溯。
两个可以提供帮助的函数:
from os.path import join, abspath
from traceback import extract_tb, format_list, format_exception_only
def spotlight(*show):
''' Return a function to be set as new sys.excepthook.
It will SHOW traceback entries for files from these directories. '''
show = tuple(join(abspath(p), '') for p in show)
def _check_file(name):
return name and name.startswith(show)
def _print(type, value, tb):
show = (fs for fs in extract_tb(tb) if _check_file(fs.filename))
fmt = format_list(show) + format_exception_only(type, value)
print(''.join(fmt), end='', file=sys.stderr)
return _print
def shadow(*hide):
''' Return a function to be set as new sys.excepthook.
It will HIDE traceback entries for files from these directories. '''
hide = tuple(join(abspath(p), '') for p in hide)
def _check_file(name):
return name and not name.startswith(hide)
def _print(type, value, tb):
show = (fs for fs in extract_tb(tb) if _check_file(fs.filename))
fmt = format_list(show) + format_exception_only(type, value)
print(''.join(fmt), end='', file=sys.stderr)
return _print
他们都使用traceback.extract_tb。它返回“从回溯对象中提取的“预处理”堆栈跟踪条目列表”;它们都是traceback.FrameSummary(命名元组)的实例。每个traceback.FrameSummary 对象都有一个filename 字段,用于存储相应文件的绝对路径。我们检查它是否以作为单独的函数参数提供的任何目录路径开始,以确定我们是否需要排除该条目(或保留它)。
这是一个示例:
标准库中的enum 模块不允许重复使用密钥,
import enum
enum.Enum('Faulty', 'a a', module=__name__)
产量
Traceback (most recent call last):
File "/home/vaultah/so/shadows/main.py", line 23, in <module>
enum.Enum('Faulty', 'a a', module=__name__)
File "/home/vaultah/cpython/Lib/enum.py", line 243, in __call__
return cls._create_(value, names, module=module, qualname=qualname, type=type, start=start)
File "/home/vaultah/cpython/Lib/enum.py", line 342, in _create_
classdict[member_name] = member_value
File "/home/vaultah/cpython/Lib/enum.py", line 72, in __setitem__
raise TypeError('Attempted to reuse key: %r' % key)
TypeError: Attempted to reuse key: 'a'
我们可以将堆栈跟踪条目限制在我们的代码中(在 /home/vaultah/so/shadows/main.py 中)。
import sys, enum
sys.excepthook = spotlight('/home/vaultah/so/shadows')
enum.Enum('Faulty', 'a a', module=__name__)
和
import sys, enum
sys.excepthook = shadow('/home/vaultah/cpython/Lib')
enum.Enum('Faulty', 'a a', module=__name__)
给出相同的结果:
File "/home/vaultah/so/shadows/main.py", line 22, in <module>
enum.Enum('Faulty', 'a a', module=__name__)
TypeError: Attempted to reuse key: 'a'
有一种方法可以排除所有站点目录(安装了第 3 方软件包的位置 - 请参阅 site.getsitepackages)
import sys, site, jinja2
sys.excepthook = shadow(*site.getsitepackages())
jinja2.Template('{%}')
# jinja2.exceptions.TemplateSyntaxError: unexpected '}'
# Generates ~30 lines, but will only display 4
注意:不要忘记从 sys.__excepthook__ 恢复 sys.excepthook。不幸的是,您将无法使用上下文管理器“修补恢复”它。