How to use Cython typed memoryviews to accept strings from Python?
Question: How can I write a Cython function that takes a byte string object (a normal
string, a bytearray, or another object that follows the [buffer
protocol](https://docs.python.org/2/c-api/buffer.html)) as a [typed
memoryview](http://docs.cython.org/src/userguide/memoryviews.html)?

According to the [Unicode and Passing
Strings](http://docs.cython.org/src/tutorial/strings.html#accepting-strings-
from-python-code) Cython tutorial page, the following should work:

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

It does work for bytearrays and other writable buffers:

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

But it doesn't work for normal strings and other read-only buffer objects:

    
    
    $ 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.
    

Looking at the generated C code, Cython is always passing the `PyBUF_WRITABLE`
flag to `PyObject_GetBuffer()`, which explains the exception.

I can manually get a view into the buffer object myself, but it's not as
convenient:

    
    
    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'
    

Am I doing something wrong, or does Cython not support coercing read-only
buffer objects (such as normal strings) into typed memoryview objects?


Answer: Despite the documentation suggesting otherwise, Cython (at least up to version
0.22) does **not** support coercing read-only buffer objects into typed
memoryview objects. Cython always passes the `PyBUF_WRITABLE` flag to
`PyObject_GetBuffer()`, even when it doesn't need write access. This causes
read-only buffer objects to raise an exception.

I [raised this issue on the Cython developer mailing
list](https://mail.python.org/pipermail/cython-
devel/2015-February/004316.html), and even included a (very rough) patch. I
never got a reply, so I assume the Cython developers are not interested in
fixing this bug.

