在 Python C API 中运行 PyRun_String() 时如何用代码注释行?

问题描述

我正在使用 Python C API 中的 PyRun_String() 来运行 Python 代码

Py_file_inputstartglobals 传递 locals 我传递用 PyDict_New() 创建的字典,对于代码字符串 str 我传递传递我的代码

例如我有一个代码

def f():
    def g():
        assert False,'TestExc'
    g()
f()

当然,此代码会引发异常并显示堆栈。我用 PyErr_Print() 打印错误获取一个堆栈:

Traceback (most recent call last):
  File "<string>",line 5,in <module>
  File "<string>",line 4,in f
  File "<string>",line 3,in g
AssertionError: TestExc

正如人们所见,此异常堆栈缺少代码行,例如,如果在纯 Python 解释器中运行相同的脚本,则它会打印下一个堆栈:

Traceback (most recent call last):
  File "test.py",in <module>
    f()
  File "test.py",in f
    g()
  File "test.py",in g
    assert False,'TestExc'
AssertionError: TestExc

所以它有代码注释,例如assert False,'TestExc' 用于堆栈的最后一行,f()g() 用于前一行。它还有文件名(但文件名不是很重要)。

有没有办法在使用 PyRun_String() 时显示代码?我希望我需要使用另一个函数,例如 PyRun_StringFlags(),它具有额外的参数 pycompilerFlags * flags,我可能可以用来告诉编译器在编译时保存附加到每一行的代码。但是我在任何地方都没有看到 pycompilerFlags 的文档,也不知道我应该通过什么。

也许还有其他有用的 pycompilerFlags 标志,例如在异常堆栈中使用 test.py 文件名而不是 <string> 会很好,可能某些人也可以调整这种行为pycompilerFlags 个值?

我还使用了 Python 内置程序中的 exec(),将带有程序代码的字符串传递给它。但是在没有代码注释的情况下得到了相同的异常堆栈。似乎如果是一些解释器范围的参数是否保存代码注释。

我还尝试使用标准 tracebacksys 模块编写特殊函数获取当前堆栈:

def GetStack():
    import traceback,sys
    frame = sys._getframe()
    extracted = traceback.extract_stack(frame)
    def AllFrames(f):
        while f is not None:
            yield f
            f = f.f_back
    all_frames = list(reversed(list(AllFrames(frame))))
    assert len(extracted) == len(all_frames)
    return [{
        'file': fs.filename,'first_line': fr.f_code.co_firstlineno,'line': fs.lineno,'func': fs.name,'code': fs._line,} for fs,fr in zip(extracted,all_frames)]

函数正确返回整个堆栈,在 code 字段内有空字符串。看起来 frame 对象在它们的 ._line 属性中没有代码注释,因为它们可能应该有,这可能是上面使用的所有函数中没有代码注释的原因。

你知道有没有什么方法可以为所有的堆栈检索/打印操作提供代码注释?除了手动编写正确的堆栈跟踪。也许至少有一些标准模块允许至少手动设置这行代码

更新。我发现 traceback 模块使用 linecache.getline(self.filename,self.lineno) (see here) 来获取代码。有人知道如何在不使用临时文件的情况下使用给定文件名的内存中的源文本填充 linecache 吗?

如果引发的异常使用 traceback 模块将异常输出到控制台,或者它有自己的格式实现,也很有趣?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)