我正在调用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+,解决方案应该是平台无关的
答案 0 :(得分:1)
好的,我深入研究了traceback
和importlib
模块,我想我找到了解决方案。这似乎适用于普通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))