[英]How do I retain source lines in tracebacks when running dynamically-compiled code objects?
Say I use compile to create a code
object from a string and a name: 假设我使用compile从字符串和名称创建
code
对象:
>>> a = compile('raise ValueError\n', '<at runtime>', 'exec')
I would like the lines within that string to appear within the traceback (note - the following is run in IDLE): 我希望该字符串中的行显示在回溯中(注意 - 以下内容在IDLE中运行):
>>> exec(a)
Traceback (most recent call last):
File "<pyshell#11>", line 1, in <module>
exec(c)
File "<at runtime>", line 1, in <module>
raise ValueError <-- This line is what I want
ValueError
Alas, they do not: 唉,他们没有:
>>> exec(a)
Traceback (most recent call last):
File "<pyshell#11>", line 1, in <module>
exec(c)
File "<at runtime>", line 1, in <module>
ValueError
Without creating a temporary file, how do I make that raise ValueError
line appear in the traceback? 在不创建临时文件的情况下,如何在跟踪中显示
raise ValueError
行?
Using the undocumented cache
member of the builtin linecache
, this seems to work: 使用内置
linecache
的未记录的cache
成员,这似乎工作:
def better_compile(src, name, mode):
# there is an example of this being set at
# https://hg.python.org/cpython/file/2.7/Lib/linecache.py#l104
from linecache import cache
cache[name] = (
len(src), None,
[line+'\n' for line in src.splitlines()], name
)
return compile(src, name, mode)
>>> c = better_compile('raise ValueError\n', '<a name>', 'exec')
>>> exec(c)
Traceback (most recent call last):
File "<pyshell#50>", line 1, in <module>
exec(c)
File "<a name>", line 1, in <module>
raise ValueError
ValueError
It turns out this is pretty much how IDLE does it 事实证明这就是IDLE如何做到的
Well, you could write your own exception handler which fills the data: 好吧,你可以编写自己的异常处理程序来填充数据:
code = """
def f1():
f2()
def f2():
1 / 0
f1()
"""
a = compile(code, '<at runtime>', 'exec')
import sys
import traceback
try:
exec(a)
except:
etype, exc, tb = sys.exc_info()
exttb = traceback.extract_tb(tb)
## Fill the missing data:
exttb2 = [(fn, lnnr, funcname,
(code.splitlines()[lnnr-1] if fn=='<at runtime>'
else line))
for fn, lnnr, funcname, line in exttb]
# Print:
sys.stderr.write('Traceback (most recent call last):\n')
for line in traceback.format_list(exttb2):
sys.stderr.write(line)
for line in traceback.format_exception_only(etype, exc):
sys.stderr.write(line)
Result: 结果:
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "<at runtime>", line 8, in <module>
f1()
File "<at runtime>", line 3, in f1
f2()
File "<at runtime>", line 6, in f2
1 / 0
ZeroDivisionError: integer division or modulo by zero
Now just wrap that compile & exec into a smart_exec
function to call every time... 现在只需将compile&exec包装成一个
smart_exec
函数,每次都调用...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.