Как использовать Cython типизированные представления памяти для принятия строк из Python?

Как написать функцию Cython, которая принимает объект строковой строки (нормальная строка, bytearray или другой объект, следующий за протоколом ) в качестве типизированное представление памяти?

В соответствии с Unicode и Passing Strings на странице руководства Cython должно работать следующее:

cpdef object printbuf(unsigned char[:] buf):
    chars = [chr(x) for x in buf]
    print repr(''.join(chars))

Он работает для bytearrays и других записываемых буферов:

$ python -c 'import test; test.printbuf(bytearray("test\0ing"))'
'test\x00ing'

Но это не работает для обычных строк и других объектов буфера только для чтения:

$ python -c 'import test; test.printbuf("test\0ing")'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
  File "test.pyx", line 1, in test.printbuf (test.c:1417)
  File "stringsource", line 614, in View.MemoryView.memoryview_cwrapper (test.c:6795)
  File "stringsource", line 321, in View.MemoryView.memoryview.__cinit__ (test.c:3341)
BufferError: Object is not writable.

Посмотрев на сгенерированный код C, Cython всегда передает флаг PyBUF_WRITABLE на PyObject_GetBuffer(), что объясняет исключение.

Я могу вручную получить представление в объект буфера самостоятельно, но это не так удобно:

from cpython.buffer cimport \
    PyBUF_SIMPLE, PyBUF_WRITABLE, \
    PyObject_CheckBuffer, PyObject_GetBuffer, PyBuffer_Release

cpdef object printbuf(object buf):
    if not PyObject_CheckBuffer(buf):
        raise TypeError("argument must follow the buffer protocol")
    cdef Py_buffer view
    PyObject_GetBuffer(buf, &view, PyBUF_SIMPLE)
    try:
        chars = [chr((<unsigned char *>view.buf)[i])
                 for i in range(view.len)]
        print repr(''.join(chars))
    finally:
        PyBuffer_Release(&view)
$ python -c 'import test; test.printbuf(bytearray("test\0ing"))'
'test\x00ing'
$ python -c 'import test; test.printbuf("test\0ing")'
'test\x00ing'

Я делаю что-то неправильно или Cython не поддерживает принудительное использование объектов буфера только для чтения (например, обычных строк) в типизированные объекты памяти?

Ответы

Ответ 1

Несмотря на документацию, указывающую на то, что Cython (по крайней мере, до версии 0.22) поддерживает не поддержку принудительного ввода объектов буфера только для чтения в типизированные объекты памяти. Cython всегда передает флаг PyBUF_WRITABLE PyObject_GetBuffer(), даже если ему не нужен доступ на запись. Это приводит к тому, что объекты буфера только для чтения создают исключение.

I поднял эту проблему в списке рассылки разработчиков Cython и даже включил (очень грубый) патч. Я никогда не получал ответа, поэтому я предполагаю, что разработчики Cython не заинтересованы в исправлении этой ошибки.