如何在回溯中重写一个特定的框架?[英] How to rewrite a specific frame in a traceback?

本文是小编为大家收集整理的关于如何在回溯中重写一个特定的框架?的处理/解决方法,可以参考本文帮助大家快速定位并解决问题,中文翻译不准确的可切换到English标签页查看源文。

问题描述

在Python中,您可以使用exec()更快地执行()来编译()字符串.但是,一旦我使用它,我们就会在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(文件名)的第二个参数
  • 我已经测试了在框架上使用Inspect和修改F_Code播放的,但是它是ReadOnly属性.

编辑:在寻求更多Sys.excepthook之后,我已经看到,在Python源代码/Trackback.c中,当Python想要显示行内容时,它们是直接fopen()直接找到文件的.根本没有可用的挂钩来显示我们自己的内容.唯一的方法是在磁盘上使用真正的假文件名创建?有人吗?

edit2:我检查了一些jinja2调试代码,它们也正在重写追溯,但没有用于内容.除钩外,我需要自定义吗?我对此的关注是因为它不在追溯本身中,如果用户/模块/其他例外,那么追踪将不包含有价值的信息.

推荐答案

进行深入搜索后,不可能,Cpython使用自己的API来确定文件在哪里,并且不能在Pure Python中进行修补.

其他推荐答案

您应该看看 this Talking 由Armin Ronacher提供.他是Jinja2的作者,在这次演讲中,他解释了如何操纵Jinja2中的堆栈痕迹.如果我没记错的话,他正在使用CTYPES来操纵Python的C级别的数据结构.在我看来,这是整个Europython 2011的最佳演讲.

其他推荐答案

这样的事情怎么样:

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()

本文地址:https://www.itbaoku.cn/post/2091150.html

问题描述

In python you can compile() string to be executed faster with exec(). But as soon as i use it, we lost information when an exception happen in the exec.

For example, here is a code snippet that calling a unknown method (for demo purposes):

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

And later, i'm calling exec on that bytecode:

exec bytecode

The traceback showed is:

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   

The "exec()" frame is now obscure. I would like to have a better exception like:

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   

Any thoughts ?

Notes:

  • I don't want to use the second argument of compile (the filename)
  • I have tested to play with inspect and modify f_code on the frame, but it's readonly attribute.

EDIT: after looking more to sys.excepthook, i've seen that in python source code/traceback.c, when python want to show the line content, they are fopen() directly the file if found. No hook available at all to display our own content. The only way would be to create in real fake filename on disk ? Anyone ?

EDIT2: i checked some jinja2 debug code, and they are rewriting traceback too, but not for content. Would i need a custom except hook ? My concerns with it is since it's not in the traceback itself, if an user/module/whatever take the exception, the traceback will not contain valuable information.

推荐答案

After a deep search, it's not possible, CPython is using its own API to determine where the file is etc, and it cannot be patched in pure Python.

其他推荐答案

You should have a look at this talk by Armin Ronacher. He's the author of Jinja2 and in this talk he explained, how he manipulates stack traces in Jinja2. If I remember correctly, he's using ctypes, to manipulate the data structures on the C level of Python. The talk was in my opinion the best talk of the whole Europython 2011 by the way.

其他推荐答案

How about something like this:

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()