python compile error_python – 从compile()获取包括SyntaxError在内的回溯信息

基本问题

看来,compile()函数引发的SyntaxErrors(和TypeErrors)不包含在sys.exc_info()返回的堆栈跟踪中,而是使用traceback.print_exc作为格式化输出的一部分打印.

例如,给定以下代码(其中filename是包含带有$flagrant语法错误行的Python代码的文件的名称):

import sys

from traceback import extract_tb

try:

with open(filename) as f:

code = compile(f.read(), filename, "exec")

except:

print "using sys.exc_info:"

tb_list = extract_tb(sys.exc_info()[2])

for f in tb_list:

print f

print "using traceback.print_exc:"

from traceback import print_exc

print_exc()

我得到以下输出(其中< scriptname>是包含上述代码的脚本的名称):

using sys.exc_info:

('', 6, 'exec_file', 'code = compile(f.read(), filename, "exec")')

using traceback.print_exc:

Traceback (most recent call last):

File "", line 6, in exec_file

code = compile(f.read(), filename, "exec")

File "", line 3

$flagrant syntax error

^

SyntaxError: invalid syntax

我的问题

我有三个问题:

>为什么sys.exc_info()的回溯不包括生成SyntaxError的帧?

> traceback.print_exc如何获取缺少的帧信息?

>在列表中保存“提取的”回溯信息(包括SyntaxError)的最佳方法是什么?是否需要使用filename和SyntaxError异常对象本身手动构造最后一个列表元素(即表示发生SyntaxError的堆栈帧的信息)?

用例示例

对于上下文,这是我试图获得完整的堆栈跟踪提取的用例.

我有一个程序,通过执行包含用户编写的Python代码的一些文件实质上实现DSL. (无论这是否是一个良好的DSL实现策略,我或多或少地坚持它.)当遇到用户代码中的错误时,我会(在某些情况下)像解释器一样保存错误以后,而不是呕吐堆栈痕迹和死亡.所以我有专门用来存储这些信息的ScriptExcInfo类.这是该类的__init__方法(稍微编辑过的版本),完成上述问题的相当丑陋的解决方法:

def __init__(self, scriptpath, add_frame):

self.exc, tb = sys.exc_info()[1:]

self.tb_list = traceback.extract_tb(tb)

if add_frame:

# Note: I'm pretty sure that the names of the linenumber and

# message attributes are undocumented, and I don't think there's

# actually a good way to access them.

if isinstance(exc, TypeError):

lineno = -1

text = exc.message

else:

lineno = exc.lineno

text = exc.text

# '?' is used as the function name since there's no function context

# in which the SyntaxError or TypeError can occur.

self.tb_list.append((scriptpath, lineno, '?', text))

else:

# Pop off the frames related to this `exec` infrastructure.

# Note that there's no straightforward way to remove the unwanted

# frames for the above case where the desired frame was explicitly

# constructed and appended to tb_list, and in fact the resulting

# list is out of order (!!!!).

while scriptpath != self.tb_list[-1][0]:

self.tb_list.pop()

请注意,“相当难看”,我的意思是这个解决方法将应该是单参数的4行__init__函数转换为需要两个参数并占用13行.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值