从追溯的顶部删除几行

时间:2017-08-19 12:03:03

标签: python python-3.x traceback python-importlib

我正在调用importlib.import_module("somemodulename")来导入一些自定义的用户定义模块。此导入可能会失败。我想向用户提供有关其失败原因的信息,因此我需要打印回溯,但它往往很长时间来自importlib模块。例如:

Traceback (most recent call last):
  File "C:\abc\cde\efg\importer.py", line 101, in load
    self.__module = importlib.import_module(self.__name)
  File "C:\Programming\Python36-32\lib\importlib\__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 978, in _gcd_import
  File "<frozen importlib._bootstrap>", line 961, in _find_and_load
  File "<frozen importlib._bootstrap>", line 950, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 655, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 678, in exec_module
  File "<frozen importlib._bootstrap>", line 205, in _call_with_frames_removed
  File "C:\abc\cde\efg\modules\testerror.py", line 3, in <module>
    x = 1 / 0  # intentional error for module testing purposes
ZeroDivisionError: division by zero

显然,大多数线路对用户不感兴趣。我希望回溯看起来像这样:

Traceback (most recent call last):
  File "C:\abc\cde\efg\modules\testerror.py", line 3, in <module>
    x = 1 / 0  # intentional error for module testing purposes
ZeroDivisionError: division by zero

但问题是我不能依赖importlib包生成的行数(这是一个可能在未来版本中更改的实现细节,可能是平台或Python安装特定的),我想要跳过,既不是自定义模块错误生成的行数(他可以自己导入一些其他模块,这可能会导致错误),我想保留。为了进一步复杂化,用户还可以调用importlib模块函数,在这种情况下这很好,应该包含在回溯中。

换句话说,我需要从回溯中删除所有importlib错误行的第一个块。除了以一种“聪明”的方式解析回溯线之外的任何想法,我认为这是一个hackish和非常脆弱的解决方案,依赖于importlib包中太多的实现细节?

注意:我使用的是Python 3.5+,解决方案应该是平台无关的

1 个答案:

答案 0 :(得分:1)

好的,我深入研究了tracebackimportlib模块,我想我找到了解决方案。这似乎适用于普通Python文件中的模块。然而,不确定冷冻包装,拉链包装等。需要对这些情况进行更多测试。

import importlib
import sys
import traceback

moduleName = "somepackage.somemodule"
try:
   importlib.import_module(moduleName)
except Exception:
    spec = importlib.util.find_spec(moduleToImport)
    if spec is None:
        # if the module is not found, then do not print traceback at all
        count = 0
    else:
        fileName = spec.loader.get_filename()
        extracts = traceback.extract_tb(sys.exc_info()[2])
        count = len(extracts)
        # find the first occurrence of the module file name
        for i, extract in enumerate(extracts):
            if extract[0] == fileName:
                break
            count -= 1
    # keep only the count of last lines
    print(traceback.format_exc(limit=-count))