如何在使用 python c-api 调用 PyErr_Print 后访问 sys.stderr
How to access sys.stderr after calling PyErr_Print with python c-api
我正在尝试通过 dll 导入从 c# 项目中使用 python c-api。
我在导入一些我认为是内置的模块时收到 ModuleNotFoundError
。
(注:我自己编译的python)
我现在有点卡住了,但我希望在下面的代码中调用 PyErr_Print()
时能得到一些额外的信息。
代码:
IntPtr modulePtr = NativeInterface.PyImport_ExecCodeModuleEx(moduleName,compiledModule, path);
if (modulePtr == IntPtr.Zero)
{
NativeInterface.PyErr_Print();
PythonException exception = PythonException.Query();
throw exception;
}
PyErr_Print 的文档声明它将用一些错误信息填充 sys.stderr
。
从我的 C# 应用程序读取此变量的最简单方法是什么?
我找不到通过 C-Api 访问 sys.stderr
的方法。但我意识到我可以通过 c-api 运行 python 脚本(参见文档中的 PyRun_String )。
所以我现在通过将 sys.path 写入文本文件来进行调试。
import sys
file = open('log.txt','w')
for path in sys.path:
file.write(i+'\n')
这个答案给出了 C 代码,因为我了解 C 而不是 C#,但我认为它应该是相当可移植的。
默认情况下 sys.stderr
写入某处的某个控制台,因此您无法有意义地尝试从中读取。但是,完全有可能替换它以重定向输出。两个明智的选择包括写入文件和写入稍后可以查询的 StringIO
对象。
运行 的 C 代码基本上等同于:
import sys
from io import StringIO # Python 3
sys.stderr = StringIO()
或在 C:
int setup_stderr() {
PyObject *io = NULL, *stringio = NULL, *stringioinstance = NULL;
int success = 0;
io = PyImport_ImportModule("io");
if (!io) goto done;
stringio = PyObject_GetAttrString(io,"StringIO");
if (!stringio) goto done;
stringioinstance = PyObject_CallFunctionObjArgs(stringio,NULL);
if (!stringioinstance) goto done;
if (PySys_SetObject("stderr",stringioinstance)==-1) goto done;
success = 1;
done:
Py_XDECREF(stringioinstance);
Py_XDECREF(stringio);
Py_XDECREF(io);
return success;
}
你 运行 这一次在你的程序开始时。
要查询 sys.stderr
的内容,您需要执行以下操作:
value = sys.stderr.getvalue()
encoded_value = value.encode() # or you could just handle the unicode output
在 C:
char* get_stderr_text() {
PyObject* stderr = PySys_GetObject("stderr"); // borrowed reference
PyObject *value = NULL, *encoded = NULL;
char* result = NULL;
char* temp_result = NULL;
Py_ssize_t size = 0;
value = PyObject_CallMethod(stderr,"getvalue",NULL);
if (!value) goto done;
// ideally should get the preferred encoding
encoded = PyUnicode_AsEncodedString(value,"utf-8","strict");
if (!encoded) goto done;
if (PyBytes_AsStringAndSize(encoded,&temp_result,&size) == -1) goto done;
size += 1;
// copy so we own the memory
result = malloc(sizeof(char)*size);
for (int i = 0; i<size; ++i) {
result[i] = temp_result[i];
}
done:
Py_XDECREF(encoded);
Py_XDECREF(value);
return result;
}
复制字符串需要付出一些努力。您可能会考虑直接使用 unicode 并使用 PyUnicode_AsUCS4Copy
.
然后您可能想在写入字符串后清除它,只需将 sys.stderr
替换为新的 StringIO
对象即可。
我正在尝试通过 dll 导入从 c# 项目中使用 python c-api。
我在导入一些我认为是内置的模块时收到 ModuleNotFoundError
。
(注:我自己编译的python)
我现在有点卡住了,但我希望在下面的代码中调用 PyErr_Print()
时能得到一些额外的信息。
代码:
IntPtr modulePtr = NativeInterface.PyImport_ExecCodeModuleEx(moduleName,compiledModule, path);
if (modulePtr == IntPtr.Zero)
{
NativeInterface.PyErr_Print();
PythonException exception = PythonException.Query();
throw exception;
}
PyErr_Print 的文档声明它将用一些错误信息填充 sys.stderr
。
从我的 C# 应用程序读取此变量的最简单方法是什么?
我找不到通过 C-Api 访问 sys.stderr
的方法。但我意识到我可以通过 c-api 运行 python 脚本(参见文档中的 PyRun_String )。
所以我现在通过将 sys.path 写入文本文件来进行调试。
import sys
file = open('log.txt','w')
for path in sys.path:
file.write(i+'\n')
这个答案给出了 C 代码,因为我了解 C 而不是 C#,但我认为它应该是相当可移植的。
默认情况下 sys.stderr
写入某处的某个控制台,因此您无法有意义地尝试从中读取。但是,完全有可能替换它以重定向输出。两个明智的选择包括写入文件和写入稍后可以查询的 StringIO
对象。
运行 的 C 代码基本上等同于:
import sys
from io import StringIO # Python 3
sys.stderr = StringIO()
或在 C:
int setup_stderr() {
PyObject *io = NULL, *stringio = NULL, *stringioinstance = NULL;
int success = 0;
io = PyImport_ImportModule("io");
if (!io) goto done;
stringio = PyObject_GetAttrString(io,"StringIO");
if (!stringio) goto done;
stringioinstance = PyObject_CallFunctionObjArgs(stringio,NULL);
if (!stringioinstance) goto done;
if (PySys_SetObject("stderr",stringioinstance)==-1) goto done;
success = 1;
done:
Py_XDECREF(stringioinstance);
Py_XDECREF(stringio);
Py_XDECREF(io);
return success;
}
你 运行 这一次在你的程序开始时。
要查询 sys.stderr
的内容,您需要执行以下操作:
value = sys.stderr.getvalue()
encoded_value = value.encode() # or you could just handle the unicode output
在 C:
char* get_stderr_text() {
PyObject* stderr = PySys_GetObject("stderr"); // borrowed reference
PyObject *value = NULL, *encoded = NULL;
char* result = NULL;
char* temp_result = NULL;
Py_ssize_t size = 0;
value = PyObject_CallMethod(stderr,"getvalue",NULL);
if (!value) goto done;
// ideally should get the preferred encoding
encoded = PyUnicode_AsEncodedString(value,"utf-8","strict");
if (!encoded) goto done;
if (PyBytes_AsStringAndSize(encoded,&temp_result,&size) == -1) goto done;
size += 1;
// copy so we own the memory
result = malloc(sizeof(char)*size);
for (int i = 0; i<size; ++i) {
result[i] = temp_result[i];
}
done:
Py_XDECREF(encoded);
Py_XDECREF(value);
return result;
}
复制字符串需要付出一些努力。您可能会考虑直接使用 unicode 并使用 PyUnicode_AsUCS4Copy
.
然后您可能想在写入字符串后清除它,只需将 sys.stderr
替换为新的 StringIO
对象即可。