在运行动态编译的代码对象时,如何在回溯中保留源代码行?

时间:2016-09-21 19:55:01

标签: python

假设我使用compile从字符串和名称创建code对象:

>>> a = compile('raise ValueError\n', '<at runtime>', 'exec')

我希望该字符串中的行显示在回溯中(注意 - 以下内容在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

唉,他们没有:

>>> exec(a)
Traceback (most recent call last):
 File "<pyshell#11>", line 1, in <module>
    exec(c)
  File "<at runtime>", line 1, in <module>
ValueError

如果不创建临时文件,如何在追溯中显示raise ValueError行?

2 个答案:

答案 0 :(得分:3)

使用内置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

事实证明这是pretty much how IDLE does it

答案 1 :(得分:0)

好吧,你可以编写自己的异常处理程序来填充数据:

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)

结果:

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

现在只需打包编译&amp;执行smart_exec函数每次调用...