Author: Armin Rigo <[email protected]>
Branch: 
Changeset: r1188:7a86941ef198
Date: 2013-03-08 00:54 +0100
http://bitbucket.org/cffi/cffi/changeset/7a86941ef198/

Log:    Give some compatibility explanation when passing a Python file
        object to a FILE argument.

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -90,6 +90,7 @@
 #define CT_CUSTOM_FIELD_POS     32768
 #define CT_IS_LONGDOUBLE        65536
 #define CT_IS_BOOL             131072
+#define _CT_IS_FILE            262144
 #define CT_PRIMITIVE_ANY  (CT_PRIMITIVE_SIGNED |        \
                            CT_PRIMITIVE_UNSIGNED |      \
                            CT_PRIMITIVE_CHAR |          \
@@ -2041,6 +2042,18 @@
     return ct_int;
 }
 
+static int
+_explicit_error_message_for_FILE(CTypeDescrObject *ctitem)
+{
+    if (!(ctitem->ct_flags & _CT_IS_FILE))
+        return 0;
+    PyErr_SetString(PyExc_TypeError,
+                    "bad argument type for 'FILE' type (note that you cannot "
+                    "pass Python files directly any more since CFFI 0.6; see "
+                    "demo/file1.py)");
+    return -1;
+}
+
 static Py_ssize_t
 _prepare_pointer_call_argument(CTypeDescrObject *ctptr, PyObject *init,
                                char **output_data)
@@ -2083,6 +2096,8 @@
     else {
         /* refuse to receive just an integer (and interpret it
            as the array size) */
+        if (_explicit_error_message_for_FILE(ctitem) < 0)
+            return -1;
         goto convert_default;
     }
 
@@ -3318,9 +3333,14 @@
 static PyObject *b_new_struct_type(PyObject *self, PyObject *args)
 {
     char *name;
+    int flag;
     if (!PyArg_ParseTuple(args, "s:new_struct_type", &name))
         return NULL;
-    return _b_struct_or_union_type("struct", name, CT_STRUCT);
+
+    flag = CT_STRUCT;
+    if (strcmp(name, "_IO_FILE") == 0 || strcmp(name, "$FILE") == 0)
+        flag |= _CT_IS_FILE;
+    return _b_struct_or_union_type("struct", name, flag);
 }
 
 static PyObject *b_new_union_type(PyObject *self, PyObject *args)
@@ -4899,8 +4919,10 @@
 static char *_cffi_to_c_pointer(PyObject *obj, CTypeDescrObject *ct)
 {
     char *result;
-    if (convert_from_object((char *)&result, ct, obj) < 0)
+    if (convert_from_object((char *)&result, ct, obj) < 0) {
+        _explicit_error_message_for_FILE(ct->ct_itemdescr);
         return NULL;
+    }
     return result;
 }
 
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -2655,6 +2655,17 @@
     c[1:3] = d
     assert list(c) == [0, 40, 50, 30, 0]
 
+def test_FILE_forbidden():
+    BFILE = new_struct_type("_IO_FILE")
+    BFILEP = new_pointer_type(BFILE)
+    BFunc = new_function_type((BFILEP,), BFILEP, False)
+    func = cast(BFunc, 0)
+    with open(__file__, "rb") as f:
+        e = py.test.raises(TypeError, func, f)
+    if '__pypy__' not in sys.builtin_module_names:
+        assert ('note that you cannot pass Python files directly '
+                'any more since CFFI 0.6') in str(e.value)
+
 def test_version():
     # this test is here mostly for PyPy
     assert __version__ == "0.6"
diff --git a/demo/file1.py b/demo/file1.py
--- a/demo/file1.py
+++ b/demo/file1.py
@@ -3,7 +3,10 @@
 
 #
 # To access FILE objects in C that correspond directly to file descriptors
-# at the Python level, just define and use fdopen() and fclose().
+# at the Python level, just define and use fdopen() and fclose().  In
+# CFFI <= 0.5 you could directly pass Python file objects, but this is
+# not supported any more: you have to build (and close) the C-level FILEs
+# explicitly.  See also 'file2.py' in the same directory for another example.
 #
 
 ffi = cffi.FFI()
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to