如何重写追溯中的特定帧?

时间:2011-11-18 11:17:49

标签: frame traceback python

在python中,你可以使用exec()更快地执行compile()字符串。但是一旦我使用它,我们就会在exec中发生异常时丢失信息。

例如,这是一个调用未知方法的代码片段(用于演示目的):

code = 'my_unknown_method()'
bytecode = compile(code, '<string>', 'exec')

后来,我在那个字节码上调用exec:

exec bytecode

回溯显示:

Traceback (most recent call last):
  File "test.py", line 3, in <module>
    exec bytecode
  File "<string>", line 1, in <module>
NameError: name 'my_unknown_method' is not defined   

“exec()”框架现在模糊不清。我希望有一个更好的例外:

Traceback (most recent call last):
  File "test.py", line 3, in <module>
    exec "my_unknown_method()"
  File "<string>", line 1, in <module>
NameError: name 'my_unknown_method' is not defined   

有什么想法吗?

注意:

  • 我不想使用compile的第二个参数(文件名)
  • 我已经测试过在框架上检查和修改f_code,但它只是readonly属性。
编辑:看了更多的sys.excepthook后,我在python源代码/ traceback.c中看到,当python想要显示行内容时,如果找到它们,则直接fopen()文件。没有可用的钩子来显示我们自己的内容。唯一的方法是在磁盘上创建真正的伪文件名?任何人?

EDIT2:我查了一些jinja2调试代码,他们也在重写回溯,但不是内容。除了钩子我需要一个自定义吗?我对它的关注是因为它不在回溯本身,如果用户/模块/任何异常,回溯将不包含有价值的信息。

3 个答案:

答案 0 :(得分:3)

你应该看看Armin Ronacher的this talk。他是Jinja2的作者,他在演讲中解释了他如何操纵Jinja2中的堆栈痕迹。如果我没记错的话,他正在使用ctypes来操纵Python的C级数据结构。在我看来,谈话是顺便提一下整个Europython 2011的最佳话题。

答案 1 :(得分:2)

经过深入搜索,这是不可能的,CPython正在使用自己的API来确定文件的位置等,并且它不能用纯Python修补。

答案 2 :(得分:0)

这样的事情怎么样:

import sys
def mkexec(code_str):
    bc = compile(code, '<string>', 'exec')
    def run():
        try:
            exec bc
        except: # Yes I know a bare except
            t, v, tb = sys.exc_info()
            raise MyUsefullException("%s raised %s" % (code_str, v))
    return run

exe = mkexec("some_unknown_something()")
exe()