1

我正在调用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从回溯中删除所有第一块错误行。除了以某种“聪明”的方式解析回溯行之外的任何想法,我认为这将是一个依赖包中太多实现细节的黑客且非常脆弱的解决方案importlib

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

4

1 回答 1

2

好的,我深入研究了tracebackandimportlib模块,我想我已经找到了解决方案。这似乎适用于普通 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))
于 2017-08-19T13:03:41.553 回答