嵌入式Python:如何将特殊字符传递给PyRun_SimpleFile

问题描述

请考虑以下代码,这些代码从C ++运行嵌入式Python脚本。它创建了一个嵌入式python模块,其功能是在执行时报告当前文件/行。

#include <Python.h>

#include <iostream>
#include <fstream>

PyObject * mymodule_meth_test(PyObject * self) {
    PyTraceBack_Here(PyEval_GetFrame());
    PyObject * exc;
    PyObject * val;
    PyObject * tb;
    PyErr_Fetch(&exc,&val,&tb);
    PyTraceBack_Print(tb,PySys_Getobject("stderr"));
    
    std::cout << "LINE is " << PyLong_AsLong(PyObject_GetAttrString(PyObject_GetAttrString(tb,"tb_frame"),"f_lineno")) << std::endl;
    std::cout << "FILE is " << PyUnicode_AsUTF8(PyObject_GetAttrString(PyObject_GetAttrString(PyObject_GetAttrString(tb,"f_code"),"co_filename")) << std::endl;

    Py_RETURN_NONE;
}

PyMethodDef module_methods[] = {
    {"test",(PyCFunction)mymodule_meth_test,METH_NOARGS,NULL},{},};

PyModuleDef module_def = {PyModuleDef_HEAD_INIT,"mymodule",NULL,-1,module_methods};

extern "C" PyObject * PyInit_mymodule() {
    PyObject * module = PyModule_Create(&module_def);
    return module;
}
    
void runScript( const std::string& script,bool utf8 )
{
    Py_SetPythonHome( L"C:\\dev\\vobs_sde\\sde\\3rdparty\\tools_ext\\python\\python38" );

    PyImport_AppendInittab("mymodule",&PyInit_mymodule);

    // Initialize the Python Interpreter
    Py_Initialize();

    FILE* file = NULL;
    open(&file,script);
    if ( file )
    {
        wchar_t* sScriptUTF8 = Py_DecodeLocale(script.c_str(),NULL);
        if ( PyRun_SimpleFile(file,(utf8) ? (const char*) sScriptUTF8 : script.c_str()) == 0 )
            std::cout << "SUCCESS" << std::endl;
        else
            std::cout << "FAIL" << std::endl;
        fclose(file);
    }
    
    Py_Finalize();
}

int main( int argc,char* argv[] )
{
    std::fstream file2;
    file2.open( "mainéfile.py",std::ios_base::out );
    file2 << "import mymodule" << std::endl;
    file2 << "mymodule.test()" << std::endl;
    file2.close();

    std::cout << std::endl << "Will fail to execute script" << std::endl;
    runScript( "mainéfile.py",false );
    std::cout << std::endl << "Will work! But FILE will be reported as 'm' instead of 'mainéfile.py'" << std::endl;
    runScript( "mainéfile.py",true );
    
    return 0;
}

此脚本输出

Will fail to execute script
FAIL
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xe9 in position 4: invalid continuation byte

Will work! But FILE will be reported as 'm' instead of 'mainéfile.py'
Traceback (most recent call last):
  File "m",line 2,in <module>
LINE is 2
FILE is m
SUCCESS

因此,如您所见:

  • 如果我将常规char*“mainéfile.py”传递给PyRun_SimpleFile,它将无法运行脚本。
  • 如果我将wchar_t“mainéfile.py”字符串传递给PyRun_SimpleFile,它可以运行脚本,但是mymodule_meth_test报告的文件名是m而预计mainéfile.py

这很可能是因为,像wchar_t一样,“mainéfile.py”是“'m',0,'a',0,...”,后来被解释为常规{{1} }变成“ m”,因为第二项被认为是EOS。

如何调用char*才能正常工作?


注意,我最终可以按以下方式致电PyRun_SimpleFile

PyRun_SimpleFile

但是,稍后在std::string utf8Str = std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(Py_DecodeLocale(script.c_str(),NULL)); if ( PyRun_SimpleFile(file,utf8Str.c_str()) == 0 ) std::cout << "SUCCESS" << std::endl; else std::cout << "FAIL" << std::endl; 中对mymodule_meth_test调用将返回PyUnicode_AsUTF8,但我找不到如何正确检索文件名的方法

解决方法

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

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

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