C Python API Extensions игнорирует open (errors = "ignore") и продолжает генерировать исключение кодирования в любом случае - PullRequest
2 голосов
/ 06 июня 2019

Имеется файл / myfiles / file_with_invalid_encoding.txt с недопустимым UTF8 как:

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

Я использую встроенную функцию Python open из C API, как показано в минимальном примере (исключая шаблон установки 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" );

Ответы [ 2 ]

1 голос
/ 06 июня 2019

PyObject_CallFunctionPy_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 и в этом случае.

0 голосов
/ 06 июня 2019

Мне удалось это исправить, заменив функцию 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;
}
...