[pypy-commit] cffi default: Progress for Python 3, but not done

arigo noreply at buildbot.pypy.org
Tue Oct 30 12:17:01 CET 2012


Author: Armin Rigo <arigo at tunes.org>
Branch: 
Changeset: r1020:adc872f1af4f
Date: 2012-10-30 12:16 +0100
http://bitbucket.org/cffi/cffi/changeset/adc872f1af4f/

Log:	Progress for Python 3, but not done

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -207,6 +207,10 @@
 
 #include "minibuffer.h"
 
+#if PY_MAJOR_VERSION >= 3
+# include "file_emulator.h"
+#endif
+
 #ifdef HAVE_WCHAR_H
 # include "wchar_helper.h"
 #endif
@@ -1729,8 +1733,10 @@
         /* from a unicode, we add the null terminator */
         length = _my_PyUnicode_SizeAsWideChar(init) + 1;
     }
-    else if (PyFile_Check(init) && (ctitem->ct_flags & CT_IS_FILE)) {
+    else if ((ctitem->ct_flags & CT_IS_FILE) && PyFile_Check(init)) {
         output_data[0] = (char *)PyFile_AsFile(init);
+        if (output_data[0] == NULL && PyErr_Occurred())
+            return -1;
         return 1;
     }
     else {
@@ -2462,9 +2468,13 @@
                 return new_simple_cdata(cdsrc->c_data, ct);
             }
         }
-        if (PyFile_Check(ob) && (ct->ct_flags & CT_POINTER) &&
-                  (ct->ct_itemdescr->ct_flags & CT_IS_FILE)) {
-            return new_simple_cdata((char *)PyFile_AsFile(ob), ct);
+        if ((ct->ct_flags & CT_POINTER) &&
+                (ct->ct_itemdescr->ct_flags & CT_IS_FILE) &&
+                PyFile_Check(ob)) {
+            FILE *f = PyFile_AsFile(ob);
+            if (f == NULL && PyErr_Occurred())
+                return NULL;
+            return new_simple_cdata((char *)f, ct);
         }
         value = _my_PyLong_AsUnsignedLongLong(ob, 0);
         if (value == (unsigned PY_LONG_LONG)-1 && PyErr_Occurred())
@@ -4599,8 +4609,9 @@
 {
     char *result;
     if (convert_from_object((char *)&result, ct, obj) < 0) {
-        if (PyFile_Check(obj) && (ct->ct_flags & CT_POINTER) &&
-                   (ct->ct_itemdescr->ct_flags & CT_IS_FILE)) {
+        if ((ct->ct_flags & CT_POINTER) &&
+                (ct->ct_itemdescr->ct_flags & CT_IS_FILE) &&
+                PyFile_Check(obj)) {
             PyErr_Clear();
             return (char *)PyFile_AsFile(obj);
         }
diff --git a/c/file_emulator.h b/c/file_emulator.h
new file mode 100644
--- /dev/null
+++ b/c/file_emulator.h
@@ -0,0 +1,78 @@
+
+/* Emulation of PyFile_Check() and PyFile_AsFile() for Python 3. */
+
+extern PyTypeObject PyIOBase_Type;
+
+
+#define PyFile_Check(p)  PyObject_IsInstance(p, (PyObject *)&PyIOBase_Type)
+
+
+void _close_file_capsule(PyObject *ob_capsule)
+{
+    FILE *f = (FILE *)PyCapsule_GetPointer(ob_capsule, "FILE");
+    if (f != NULL)
+        fclose(f);
+}
+
+
+static FILE *PyFile_AsFile(PyObject *ob_file)
+{
+    PyObject *ob, *ob_capsule = NULL, *ob_mode = NULL;
+    FILE *f = NULL;
+    int fd;
+    char *mode;
+    _Py_IDENTIFIER(flush);
+    _Py_IDENTIFIER(mode);
+    _Py_IDENTIFIER(__cffi_FILE);
+
+    ob = _PyObject_CallMethodId(ob_file, &PyId_flush, NULL);
+    if (ob == NULL)
+        goto fail;
+    Py_DECREF(ob);
+
+    ob_capsule = _PyObject_GetAttrId(ob_file, &PyId___cffi_FILE);
+    if (ob_capsule == NULL) {
+        PyErr_Clear();
+
+        fd = PyObject_AsFileDescriptor(ob_file);
+        if (fd < 0)
+            goto fail;
+
+        ob_mode = _PyObject_GetAttrId(ob_file, &PyId_mode);
+        if (ob_mode == NULL)
+            goto fail;
+        mode = PyText_AsUTF8(ob_mode);
+        if (mode == NULL)
+            goto fail;
+
+        fd = dup(fd);
+        if (fd < 0) {
+            PyErr_SetFromErrno(PyExc_OSError);
+            goto fail;
+        }
+
+        f = fdopen(fd, mode);
+        if (f == NULL) {
+            close(fd);
+            PyErr_SetFromErrno(PyExc_OSError);
+            goto fail;
+        }
+        Py_DECREF(ob_mode);
+        ob_mode = NULL;
+
+        ob_capsule = PyCapsule_New(f, "FILE", _close_file_capsule);
+        if (ob_capsule == NULL) {
+            fclose(f);
+            goto fail;
+        }
+
+        if (_PyObject_SetAttrId(ob_file, &PyId___cffi_FILE, ob_capsule) < 0)
+            goto fail;
+    }
+    return PyCapsule_GetPointer(ob_capsule, "FILE");
+
+ fail:
+    Py_XDECREF(ob_mode);
+    Py_XDECREF(ob_capsule);
+    return NULL;
+}
diff --git a/c/minibuffer.h b/c/minibuffer.h
--- a/c/minibuffer.h
+++ b/c/minibuffer.h
@@ -121,6 +121,83 @@
 };
 
 #if PY_MAJOR_VERSION >= 3
+/* pfffffffffffff pages of copy-paste from listobject.c */
+static PyObject *mb_subscript(MiniBufferObj *self, PyObject *item)
+{
+    if (PyIndex_Check(item)) {
+        Py_ssize_t i;
+        i = PyNumber_AsSsize_t(item, PyExc_IndexError);
+        if (i == -1 && PyErr_Occurred())
+            return NULL;
+        if (i < 0)
+            i += self->mb_size;
+        return mb_item(self, i);
+    }
+    else if (PySlice_Check(item)) {
+        Py_ssize_t start, stop, step, slicelength;
+
+        if (PySlice_GetIndicesEx(item, self->mb_size,
+                         &start, &stop, &step, &slicelength) < 0)
+            return NULL;
+
+        if (step == 1)
+            return mb_slice(self, start, stop);
+        else {
+            PyErr_SetString(PyExc_TypeError,
+                            "buffer doesn't support slicing with step != 1");
+            return NULL;
+        }
+    }
+    else {
+        PyErr_Format(PyExc_TypeError,
+                     "buffer indices must be integers, not %.200s",
+                     item->ob_type->tp_name);
+        return NULL;
+    }
+}
+static int
+mb_ass_subscript(MiniBufferObj* self, PyObject* item, PyObject* value)
+{
+    if (PyIndex_Check(item)) {
+        Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
+        if (i == -1 && PyErr_Occurred())
+            return -1;
+        if (i < 0)
+            i += self->mb_size;
+        return mb_ass_item(self, i, value);
+    }
+    else if (PySlice_Check(item)) {
+        Py_ssize_t start, stop, step, slicelength;
+
+        if (PySlice_GetIndicesEx(item, self->mb_size,
+                         &start, &stop, &step, &slicelength) < 0) {
+            return -1;
+        }
+
+        if (step == 1)
+            return mb_ass_slice(self, start, stop, value);
+        else {
+            PyErr_SetString(PyExc_TypeError,
+                            "buffer doesn't support slicing with step != 1");
+            return -1;
+        }
+    }
+    else {
+        PyErr_Format(PyExc_TypeError,
+                     "buffer indices must be integers, not %.200s",
+                     item->ob_type->tp_name);
+        return -1;
+    }
+}
+
+static PyMappingMethods mb_as_mapping = {
+    (lenfunc)mb_length, /*mp_length*/
+    (binaryfunc)mb_subscript, /*mp_subscript*/
+    (objobjargproc)mb_ass_subscript, /*mp_ass_subscript*/
+};
+#endif
+
+#if PY_MAJOR_VERSION >= 3
 # define MINIBUF_TPFLAGS (Py_TPFLAGS_DEFAULT)
 #else
 # define MINIBUF_TPFLAGS (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GETCHARBUFFER | Py_TPFLAGS_HAVE_NEWBUFFER)
@@ -139,7 +216,11 @@
     0,                                          /* tp_repr */
     0,                                          /* tp_as_number */
     &mb_as_sequence,                            /* tp_as_sequence */
+#if PY_MAJOR_VERSION < 3
     0,                                          /* tp_as_mapping */
+#else
+    &mb_as_mapping,                             /* tp_as_mapping */
+#endif
     0,                                          /* tp_hash */
     0,                                          /* tp_call */
     0,                                          /* tp_str */
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -10,6 +10,7 @@
     mandatory_b_prefix = ''
     mandatory_u_prefix = 'u'
     bytechr = chr
+    bitem2bchr = lambda x: x
     class U(object):
         def __add__(self, other):
             return eval('u'+repr(other).replace(r'\\u', r'\u')
@@ -23,6 +24,7 @@
     mandatory_b_prefix = 'b'
     mandatory_u_prefix = ''
     bytechr = lambda n: bytes([n])
+    bitem2bchr = bytechr
     u = ""
 
 def size_of_int():
@@ -1808,7 +1810,10 @@
     assert (p < s) ^ (p > s)
 
 def test_buffer():
-    import __builtin__
+    try:
+        import __builtin__
+    except ImportError:
+        import builtins as __builtin__
     BShort = new_primitive_type("short")
     s = newp(new_pointer_type(BShort), 100)
     assert sizeof(s) == size_of_ptr()
@@ -1830,7 +1835,7 @@
         except IndexError:
             py.test.raises(IndexError, "buf[i]")
         else:
-            assert buf[i] == expected
+            assert buf[i] == bitem2bchr(expected)
     # --mb_slice--
     assert buf[:] == b"hi there\x00"
     for i in range(-12, 12):
@@ -1839,33 +1844,34 @@
         for j in range(-12, 12):
             assert buf[i:j] == b"hi there\x00"[i:j]
     # --misc--
-    assert list(buf) == list(b"hi there\x00")
+    assert list(buf) == list(map(bitem2bchr, b"hi there\x00"))
     # --mb_as_buffer--
-    py.test.raises(TypeError, __builtin__.buffer, c)
-    bf1 = __builtin__.buffer(buf)
-    assert len(bf1) == len(buf) and bf1[3] == "t"
+    if hasattr(__builtin__, 'buffer'):          # Python <= 2.7
+        py.test.raises(TypeError, __builtin__.buffer, c)
+        bf1 = __builtin__.buffer(buf)
+        assert len(bf1) == len(buf) and bf1[3] == "t"
     if hasattr(__builtin__, 'memoryview'):      # Python >= 2.7
         py.test.raises(TypeError, memoryview, c)
         mv1 = memoryview(buf)
-        assert len(mv1) == len(buf) and mv1[3] == "t"
+        assert len(mv1) == len(buf) and mv1[3] in (b"t", ord(b"t"))
     # --mb_ass_item--
-    expected = list(b"hi there\x00")
+    expected = list(map(bitem2bchr, b"hi there\x00"))
     for i in range(-12, 12):
         try:
-            expected[i] = chr(i & 0xff)
+            expected[i] = bytechr(i & 0xff)
         except IndexError:
-            py.test.raises(IndexError, "buf[i] = chr(i & 0xff)")
+            py.test.raises(IndexError, "buf[i] = bytechr(i & 0xff)")
         else:
-            buf[i] = chr(i & 0xff)
+            buf[i] = bytechr(i & 0xff)
         assert list(buf) == expected
     # --mb_ass_slice--
     buf[:] = b"hi there\x00"
-    assert list(buf) == list(c) == list(b"hi there\x00")
+    assert list(buf) == list(c) == list(map(bitem2bchr, b"hi there\x00"))
     py.test.raises(ValueError, 'buf[:] = b"shorter"')
     py.test.raises(ValueError, 'buf[:] = b"this is much too long!"')
     buf[4:2] = b""   # no effect, but should work
     assert buf[:] == b"hi there\x00"
-    expected = list(b"hi there\x00")
+    expected = list(map(bitem2bchr, b"hi there\x00"))
     x = 0
     for i in range(-12, 12):
         for j in range(-12, 12):
@@ -1873,10 +1879,10 @@
             stop  = j if j >= 0 else j + len(buf)
             start = max(0, min(len(buf), start))
             stop  = max(0, min(len(buf), stop))
-            sample = chr(x & 0xff) * (stop - start)
+            sample = bytechr(x & 0xff) * (stop - start)
             x += 1
             buf[i:j] = sample
-            expected[i:j] = sample
+            expected[i:j] = map(bitem2bchr, sample)
             assert list(buf) == expected
 
 def test_getcname():
@@ -2249,6 +2255,11 @@
     assert len(p) == 4
     assert list(p) == [b"f", b"o", b"o", b"\x00"]
 
+# XXX hack
+if sys.version_info >= (3,):
+    import posix, io
+    posix.fdopen = io.open
+
 def test_FILE():
     if sys.platform == "win32":
         py.test.skip("testing FILE not implemented")
@@ -2266,8 +2277,8 @@
     #
     import posix
     fdr, fdw = posix.pipe()
-    fr1 = posix.fdopen(fdr, 'r', 256)
-    fw1 = posix.fdopen(fdw, 'w', 256)
+    fr1 = posix.fdopen(fdr, 'rb', 256)
+    fw1 = posix.fdopen(fdw, 'wb', 256)
     #
     fw1.write(b"X")
     res = fputs(b"hello world\n", fw1)


More information about the pypy-commit mailing list