【问题标题】:C Python API Extensions is ignoring open(errors="ignore") and keeps throwing the encoding exception anywaysC Python API 扩展忽略了 open(errors="ignore") 并继续抛出编码异常
【发布时间】:2019-10-22 06:44:58
【问题描述】:

给定一个带有无效 UTF8 的文件 /myfiles/file_with_invalid_encoding.txt

parse this correctly
Føö»BÃ¥r
also parse this correctly

我正在使用 C API 中的内置 Python open 函数,如下最小示例(不包括 C Python 设置样板):

const char* filepath = "/myfiles/file_with_invalid_encoding.txt";
PyObject* iomodule = PyImport_ImportModule( "builtins" );

if( iomodule == NULL ) {
    PyErr_PrintEx(100); return;
}
PyObject* openfunction = PyObject_GetAttrString( iomodule, "open" );

if( openfunction == NULL ) {
    PyErr_PrintEx(100); return;
}

PyObject* openfile = PyObject_CallFunction( openfunction, 
       "s", filepath, "s", "r", "i", -1, "s", "UTF8", "s", "ignore" );

if( openfile == NULL ) {
    PyErr_PrintEx(100); return;
}

PyObject* iterfunction = PyObject_GetAttrString( openfile, "__iter__" );
Py_DECREF( openfunction );

if( iterfunction == NULL ) {
    PyErr_PrintEx(100); return;
}
PyObject* openfileresult = PyObject_CallObject( iterfunction, NULL );
Py_DECREF( iterfunction );

if( openfileresult == NULL ) {
    PyErr_PrintEx(100); return;
}
PyObject* fileiterator = PyObject_GetAttrString( openfile, "__next__" );
Py_DECREF( openfileresult );
if( fileiterator == NULL ) {
    PyErr_PrintEx(100); return;
}
PyObject* readline;
std::cout << "Here 1!" << std::endl;

while( ( readline = PyObject_CallObject( fileiterator, NULL ) ) != NULL ) {
    std::cout << "Here 2!" << std::endl;
    std::cout << PyUnicode_AsUTF8( readline ) << std::endl;
    Py_DECREF( readline );
}
PyErr_PrintEx(100);
PyErr_Clear();

PyObject* closefunction = PyObject_GetAttrString( openfile, "close" );

if( closefunction == NULL ) {
    PyErr_PrintEx(100); return;
}

PyObject* closefileresult = PyObject_CallObject( closefunction, NULL );
Py_DECREF( closefunction );

if( closefileresult == NULL ) {
    PyErr_PrintEx(100); return;
}

Py_XDECREF( closefileresult );
Py_XDECREF( iomodule );
Py_XDECREF( openfile );
Py_XDECREF( fileiterator );

我正在调用 open 函数传递 ignore 参数以忽略编码错误,但 Python 忽略我并在发现无效 UTF8 字符时不断抛出编码异常:

Here 1!
Traceback (most recent call last):
  File "/usr/lib/python3.6/codecs.py", line 321, in decode
    (result, consumed) = self._buffer_decode(data, self.errors, final)
UnicodeDecodeError: 'utf-8' codec can't decode byte 0xbb in position 26: invalid start byte

正如你在上面和下面看到的,当我调用builtins.open() 函数时,我传递了ignore 参数,但它没有任何效果。我也尝试将ignore 更改为replace,但 C Python 始终抛出异常:

PyObject* openfile = PyObject_CallFunction( openfunction, 
       "s", filepath, "s", "r", "i", -1, "s", "UTF8", "s", "ignore" );

【问题讨论】:

  • 我不确定这是您的only问题,但是在您通过调用openfunction 设置openfile 的初始值之后,它似乎是错误的,它是后者的值,而不是前者,您测试为 null。
  • 谢谢,我修复了它并重新测试了程序。但是编码问题仍然存在。我还添加了"Here 1!""Here 2!",运行它时,只有Here 1! 出现在堆栈跟踪之前。

标签: python c cpython python-c-api


【解决方案1】:

PyObject_CallFunction(和Py_BuildValue 等)采用一个格式字符串来描述所有参数。当你这样做时

PyObject* openfile = PyObject_CallFunction( openfunction, 
   "s", filepath, "s", "r", "i", -1, "s", "UTF8", "s", "ignore" );

您说过“一个字符串参数”,filepath 之后的所有参数都被忽略。相反,您应该这样做:

PyObject* openfile = PyObject_CallFunction( openfunction, 
   "ssiss", filepath, "r", -1, "UTF8", "ignore" );

说“5 个参数:2 个字符串、int 和另外两个字符串”。即使您选择使用其他PyObject_Call* 函数之一,您也会发现以这种方式使用Py_BuildValue 也更容易。

【讨论】:

    【解决方案2】:

    我设法通过将函数 PyObject_CallFunction 替换为 PyObject_CallFunctionObjArgs 函数来修复它:

    PyObject* openfile = PyObject_CallFunction( openfunction, 
           "s", filepath, "s", "r", "i", -1, "s", "UTF8", "s", "ignore" );
    // -->
    PyObject* filepathpy = Py_BuildValue( "s", filepath );
    PyObject* openmodepy = Py_BuildValue( "s", "r" );
    PyObject* buffersizepy = Py_BuildValue( "i", -1 );
    PyObject* encodingpy = Py_BuildValue( "s", "UTF-8" );
    PyObject* ignorepy = Py_BuildValue( "s", "ignore" );
    
    PyObject* openfile = PyObject_CallFunctionObjArgs( openfunction, 
            filepathpy, openmodepy, buffersizepy, encodingpy, ignorepy, NULL );
    

    C Python 喜欢的长版本:

    PyObject* filepathpy = Py_BuildValue( "s", filepath );
    if( filepathpy == NULL ) {
        PyErr_PrintEx(100); return;
    }
    
    PyObject* openmodepy = Py_BuildValue( "s", "r" );
    if( openmodepy == NULL ) {
        PyErr_PrintEx(100); return;
    }
    
    PyObject* buffersizepy = Py_BuildValue( "i", -1 );
    if( buffersizepy == NULL ) {
        PyErr_PrintEx(100); return;
    }
    
    PyObject* encodingpy = Py_BuildValue( "s", "UTF-8" );
    if( encodingpy == NULL ) {
        PyErr_PrintEx(100); return;
    }
    
    PyObject* ignorepy = Py_BuildValue( "s", "ignore" );
    if( ignorepy == NULL ) {
        PyErr_PrintEx(100); return;
    }
    
    PyObject* openfile = PyObject_CallFunctionObjArgs( openfunction,
            filepathpy, openmodepy, buffersizepy, encodingpy, ignorepy, NULL );
    
    Py_DECREF( filepathpy );
    Py_DECREF( openmodepy );
    Py_DECREF( buffersizepy );
    Py_DECREF( encodingpy );
    Py_DECREF( ignorepy );
    
    if( openfile == NULL ) {
        PyErr_PrintEx(100); return;
    }
    

    【讨论】:

      猜你喜欢
      • 2011-12-01
      • 1970-01-01
      • 2010-10-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-02-17
      • 2021-05-13
      • 1970-01-01
      相关资源
      最近更新 更多