Armin Rigo avatar Armin Rigo committed 14eff35

issue35: meh, Python 2.7 decided to drop complete support for 'buffer'
object at the same time that 'memoryview' was added. Work around.

Comments (0)

Files changed (4)

c/_cffi_backend.c

         return NULL;
     }
     /*WRITE(cd->c_data, size)*/
-#if PY_MAJOR_VERSION < 3
+#if PY_MAJOR_VERSION < 3 && !defined(PyMemoryView_Check)   /* Python 2.6 */
     return PyBuffer_FromReadWriteMemory(cd->c_data, size);
 #else
     {
     type_or_class = "type"
     mandatory_b_prefix = ''
     mandatory_u_prefix = 'u'
-    readbuf = str
+    readbuf = lambda buf: buf[:]
     bufchar = lambda x: x
     bytechr = chr
     class U(object):
     c[2] = b'-'
     buf[:2] = b'HI'
     assert string(c) == b'HI-there'
-    if sys.version_info < (3,) or sys.version_info >= (3, 3):
+    if sys.version_info < (2, 7) or sys.version_info >= (3, 3):
         assert buf[:4:2] == b'H-'
         if '__pypy__' not in sys.builtin_module_names:
             # XXX pypy doesn't support the following assignment so far

cffi/backend_ctypes.py

         return b._to_string(maxlen)
 
     def buffer(self, bptr, size=-1):
-        if sys.version_info >= (3,):
+        if sys.version_info >= (2, 7):
             # buf = bptr._as_ctype_ptr
             # return memoryview(buf.contents)
             if isinstance(bptr, CTypesGenericPtr):

testing/backend_tests.py

             b = ffi.buffer(a)
         except NotImplementedError as e:
             py.test.skip(str(e))
-        if sys.version < '3':
+        if sys.version_info < (2, 7):
             assert type(b) is buffer
             content = str(b)
         else:
             b = ffi.buffer(a)
         except NotImplementedError as e:
             py.test.skip(str(e))
-        if sys.version < '3':
+        if sys.version_info < (2, 7):
             assert type(b) is buffer
             content = str(b)
         else:
             b = ffi.buffer(a, 1)
         except NotImplementedError as e:
             py.test.skip(str(e))
-        if sys.version < '3':
+        if sys.version_info < (2, 7):
             assert type(b) is buffer
             content = str(b)
         else:
             ffi.buffer(a1)
         except NotImplementedError as e:
             py.test.skip(str(e))
-        if sys.version < '3':
-            assert str(ffi.buffer(a1)) == str(ffi.buffer(a2, 4*10))
+        if sys.version_info < (3,):
+            assert ffi.buffer(a1)[:] == ffi.buffer(a2, 4*10)[:]
         else:
             assert ffi.buffer(a1).tobytes() == ffi.buffer(a2, 4*10).tobytes()
 
         f.close()
         os.unlink(filename)
 
+    def test_ffi_buffer_with_io(self):
+        ffi = FFI(backend=self.Backend())
+        import io, array
+        f = io.BytesIO()
+        a = ffi.new("int[]", list(range(1005)))
+        try:
+            ffi.buffer(a, 512)
+        except NotImplementedError as e:
+            py.test.skip(str(e))
+        f.write(ffi.buffer(a, 1000 * ffi.sizeof("int")))
+        f.seek(0)
+        assert f.read() == array.array('i', range(1000)).tostring()
+        f.seek(0)
+        b = ffi.new("int[]", 1005)
+        f.readinto(ffi.buffer(b, 1000 * ffi.sizeof("int")))
+        assert list(a)[:1000] + [0] * (len(a)-1000) == list(b)
+        f.close()
+
     def test_array_in_struct(self):
         ffi = FFI(backend=self.Backend())
         ffi.cdef("struct foo_s { int len; short data[5]; };")
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.