gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 20:58:43 26 4
gpt4 key购买 nike

基本问题

看来 SyntaxError s(和TypeError s)由compile()引发sys.exc_info() 返回的堆栈跟踪中包含函数, 但打印为使用 traceback.print_exc 的格式化输出的一部分.

例子

例如,给定以下代码(其中 filename 是包含带有 $ flagrant syntax error 行的 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:
('<scriptname>', 6, 'exec_file', 'code = compile(f.read(), filename, "exec")')
using traceback.print_exc:
Traceback (most recent call last):
File "<scriptname>", line 6, in exec_file
code = compile(f.read(), filename, "exec")
File "<filename>", line 3
$ flagrant syntax error
^
SyntaxError: invalid syntax

我的问题

我有三个问题:

  • 为什么不从 sys.exc_info() 追溯?包括 SyntaxError 所在的框架是生成的?
  • 如何traceback.print_exc获取丢失的帧信息?
  • 保存“提取的”回溯信息(包括 SyntaxError)的最佳方式是什么? ,在列表中?最后一个列表元素(即来自堆栈帧的信息表示 SyntaxError 发生的位置)是否需要使用 filename 手动构造?和 SyntaxError异常对象本身?

示例用例

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

我有一个程序,基本上通过 exec 实现 DSL正在处理一些包含用户编写的 Python 代码的文件。 (不管这是否是一个好的 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 行的函数。

最佳答案

两种方法之间唯一的区别是print_exc() 打印格式化异常。对于包含格式化信息的 SyntaxError,异常中包含导致问题的实际行。

对于回溯本身,print_exc() 使用 sys.exc_info()[2],您已经使用相同的信息来生成回溯。换句话说,它没有得到比你已经得到的更多的信息,但是你忽略了异常信息本身:

>>> import traceback
>>> try:
... compile('Hmmm, nope!', '<stdin>', 'exec')
... except SyntaxError as e:
... print ''.join(traceback.format_exception_only(type(e), e))
...
File "<stdin>", line 1
Hmmm, nope!
^
SyntaxError: invalid syntax

这里的traceback.format_exception_only()是一个未记录的函数,被traceback.print_exc()用来格式化异常值。所有信息都在那里供您提取异常本身:

>>> dir(e)
['__class__', '__delattr__', '__dict__', '__doc__', '__format__', '__getattribute__', '__getitem__', '__getslice__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', '__unicode__', 'args', 'filename', 'lineno', 'message', 'msg', 'offset', 'print_file_and_line', 'text']
>>> e.args
('invalid syntax', ('<stdin>', 1, 11, 'Hmmm, nope!\n'))
>>> e.filename, e.lineno, e.offset, e.text
('<stdin>', 1, 11, 'Hmmm, nope!\n')

另请参阅 traceback.print_exception() 的文档:

(3) if type is SyntaxError and value has the appropriate format, it prints the line where the syntax error occurred with a caret indicating the approximate position of the error.

SyntaxError documentation :

Instances of this class have attributes filename, lineno, offset and text for easier access to the details. str() of the exception instance returns only the message.

语法错误的行不包含在回溯中是合乎逻辑的;语法错误的代码无法执行,因此没有为它创建执行框架。异常是由最底层的执行框架 compile() 函数抛出的。

因此,您坚持使用“丑陋”的方法;这是处理 SyntaxError 异常的正确方法。但是,属性记录的。

请注意,exception.message 通常设置为 exception.args[0],而 str(exception) 通常 给你相同的消息(如果 args 更长你得到 str(exception.args) 而不是,尽管一些异常类型提供自定义 __str__ 通常只会给你 exception.args[0])。

关于python - 从 compile() 获取包括 SyntaxError 在内的回溯信息,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27364868/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com