Author: Armin Rigo <ar...@tunes.org>
Branch: release-0.9
Changeset: r1669:7e52019c7511
Date: 2015-03-13 10:00 +0100
http://bitbucket.org/cffi/cffi/changeset/7e52019c7511/

Log:    hg merge default

diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c
--- a/c/_cffi_backend.c
+++ b/c/_cffi_backend.c
@@ -5142,10 +5142,13 @@
        'view->obj'. */
     PyBufferProcs *pb = x->ob_type->tp_as_buffer;
     if (pb && !pb->bf_releasebuffer) {
-        /* try all three in some vaguely sensible order */
-        readbufferproc proc = (readbufferproc)pb->bf_getwritebuffer;
+        /* we used to try all three in some vaguely sensible order,
+           i.e. first the write.  But trying to call the write on a
+           read-only buffer fails with TypeError.  So we use a less-
+           sensible order now.  See test_from_buffer_more_cases. */
+        readbufferproc proc = (readbufferproc)pb->bf_getreadbuffer;
         if (!proc)     proc = (readbufferproc)pb->bf_getcharbuffer;
-        if (!proc)     proc = (readbufferproc)pb->bf_getreadbuffer;
+        if (!proc)     proc = (readbufferproc)pb->bf_getwritebuffer;
         if (proc && pb->bf_getsegcount) {
             if ((*pb->bf_getsegcount)(x, NULL) != 1) {
                 PyErr_SetString(PyExc_TypeError,
@@ -5173,6 +5176,40 @@
     return 0;
 }
 
+static int invalid_input_buffer_type(PyObject *x)
+{
+#if PY_MAJOR_VERSION < 3
+    if (PyBuffer_Check(x)) {
+        /* XXX fish fish fish in an inofficial way */
+        typedef struct {
+            PyObject_HEAD
+            PyObject *b_base;
+        } _my_PyBufferObject;
+
+        _my_PyBufferObject *b = (_my_PyBufferObject *)x;
+        x = b->b_base;
+        if (x == NULL)
+            return 0;
+    }
+    else
+#endif
+#if PY_MAJOR_VERSION > 2 || PY_MINOR_VERSION > 6
+    if (PyMemoryView_Check(x)) {
+        x = PyMemoryView_GET_BASE(x);
+        if (x == NULL)
+            return 0;
+    }
+    else
+#endif
+        ;
+
+    if (PyBytes_Check(x) || PyUnicode_Check(x))
+        return 1;
+    if (PyByteArray_Check(x)) /* <= this one here for PyPy compatibility */
+        return 1;
+    return 0;
+}
+
 static PyObject *b_from_buffer(PyObject *self, PyObject *args)
 {
     CTypeDescrObject *ct;
@@ -5188,8 +5225,7 @@
         return NULL;
     }
 
-    if (PyBytes_Check(x) || PyText_Check(x) ||
-        PyByteArray_Check(x) /* <= this one here for PyPy compatibility */ ) {
+    if (invalid_input_buffer_type(x)) {
         PyErr_SetString(PyExc_TypeError,
                         "from_buffer() cannot return the address of the "
                         "raw string within a "STR_OR_BYTES" or unicode or "
@@ -5441,6 +5477,67 @@
     return PyLong_FromVoidPtr(f);
 }
 
+#if PY_MAJOR_VERSION < 3
+static Py_ssize_t _test_segcountproc(PyObject *o, Py_ssize_t *ignored)
+{
+    return 1;
+}
+static Py_ssize_t _test_getreadbuf(PyObject *o, Py_ssize_t i, void **r)
+{
+    static char buf[] = "RDB";
+    *r = buf;
+    return 3;
+}
+static Py_ssize_t _test_getwritebuf(PyObject *o, Py_ssize_t i, void **r)
+{
+    static char buf[] = "WRB";
+    *r = buf;
+    return 3;
+}
+static Py_ssize_t _test_getcharbuf(PyObject *o, Py_ssize_t i, char **r)
+{
+    static char buf[] = "CHB";
+    *r = buf;
+    return 3;
+}
+#endif
+static int _test_getbuf(PyObject *self, Py_buffer *view, int flags)
+{
+    static char buf[] = "GTB";
+    return PyBuffer_FillInfo(view, self, buf, 3, /*readonly=*/0, flags);
+}
+static int _test_getbuf_ro(PyObject *self, Py_buffer *view, int flags)
+{
+    static char buf[] = "ROB";
+    return PyBuffer_FillInfo(view, self, buf, 3, /*readonly=*/1, flags);
+}
+
+
+static PyObject *b__testbuff(PyObject *self, PyObject *args)
+{
+    /* for testing only */
+    int methods;
+    PyTypeObject *obj;
+    if (!PyArg_ParseTuple(args, "O!i|_testbuff", &PyType_Type, &obj, &methods))
+        return NULL;
+
+    assert(obj->tp_as_buffer != NULL);
+
+#if PY_MAJOR_VERSION < 3
+    obj->tp_as_buffer->bf_getsegcount = &_test_segcountproc;
+    obj->tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER;
+    obj->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER;
+    if (methods & 1)  obj->tp_as_buffer->bf_getreadbuffer  = &_test_getreadbuf;
+    if (methods & 2)  obj->tp_as_buffer->bf_getwritebuffer = 
&_test_getwritebuf;
+    if (methods & 4)  obj->tp_as_buffer->bf_getcharbuffer  = &_test_getcharbuf;
+#endif
+    if (methods & 8)  obj->tp_as_buffer->bf_getbuffer      = &_test_getbuf;
+    if (methods & 16) obj->tp_as_buffer->bf_getbuffer      = &_test_getbuf_ro;
+
+    Py_INCREF(Py_None);
+    return Py_None;
+}
+
 static PyMethodDef FFIBackendMethods[] = {
     {"load_library", b_load_library, METH_VARARGS},
     {"new_primitive_type", b_new_primitive_type, METH_VARARGS},
@@ -5473,6 +5570,7 @@
 #endif
     {"_get_types", b__get_types, METH_NOARGS},
     {"_testfunc", b__testfunc, METH_VARARGS},
+    {"_testbuff", b__testbuff, METH_VARARGS},
     {NULL,     NULL}    /* Sentinel */
 };
 
diff --git a/c/test_c.py b/c/test_c.py
--- a/c/test_c.py
+++ b/c/test_c.py
@@ -3258,6 +3258,88 @@
     cast(p, c)[1] += 500
     assert list(a) == [10000, 20500, 30000]
 
+def test_from_buffer_not_str_unicode_bytearray():
+    BChar = new_primitive_type("char")
+    BCharP = new_pointer_type(BChar)
+    BCharA = new_array_type(BCharP, None)
+    py.test.raises(TypeError, from_buffer, BCharA, b"foo")
+    py.test.raises(TypeError, from_buffer, BCharA, u"foo")
+    py.test.raises(TypeError, from_buffer, BCharA, bytearray(b"foo"))
+    try:
+        from __builtin__ import buffer
+    except ImportError:
+        pass
+    else:
+        py.test.raises(TypeError, from_buffer, BCharA, buffer(b"foo"))
+        py.test.raises(TypeError, from_buffer, BCharA, buffer(u"foo"))
+        py.test.raises(TypeError, from_buffer, BCharA,
+                       buffer(bytearray(b"foo")))
+    try:
+        from __builtin__ import memoryview
+    except ImportError:
+        pass
+    else:
+        py.test.raises(TypeError, from_buffer, BCharA, memoryview(b"foo"))
+        py.test.raises(TypeError, from_buffer, BCharA,
+                       memoryview(bytearray(b"foo")))
+
+def test_from_buffer_more_cases():
+    try:
+        from _cffi_backend import _testbuff
+    except ImportError:
+        py.test.skip("not for pypy")
+    BChar = new_primitive_type("char")
+    BCharP = new_pointer_type(BChar)
+    BCharA = new_array_type(BCharP, None)
+    #
+    def check1(bufobj, expected):
+        c = from_buffer(BCharA, bufobj)
+        assert typeof(c) is BCharA
+        if sys.version_info >= (3,):
+            expected = [bytes(c, "ascii") for c in expected]
+        assert list(c) == list(expected)
+    #
+    def check(methods, expected, expected_for_memoryview=None):
+        if sys.version_info >= (3,):
+            if methods <= 7:
+                return
+            if expected_for_memoryview is not None:
+                expected = expected_for_memoryview
+        class X(object):
+            pass
+        _testbuff(X, methods)
+        bufobj = X()
+        check1(bufobj, expected)
+        try:
+            from __builtin__ import buffer
+            bufobjb = buffer(bufobj)
+        except (TypeError, ImportError):
+            pass
+        else:
+            check1(bufobjb, expected)
+        try:
+            bufobjm = memoryview(bufobj)
+        except (TypeError, NameError):
+            pass
+        else:
+            check1(bufobjm, expected_for_memoryview or expected)
+    #
+    check(1, "RDB")
+    check(2, "WRB")
+    check(4, "CHB")
+    check(8, "GTB")
+    check(16, "ROB")
+    #
+    check(1 | 2,  "RDB")
+    check(1 | 4,  "RDB")
+    check(2 | 4,  "CHB")
+    check(1 | 8,  "RDB", "GTB")
+    check(1 | 16, "RDB", "ROB")
+    check(2 | 8,  "WRB", "GTB")
+    check(2 | 16, "WRB", "ROB")
+    check(4 | 8,  "CHB", "GTB")
+    check(4 | 16, "CHB", "ROB")
+
 def test_version():
     # this test is here mostly for PyPy
     assert __version__ == "0.9.1"
diff --git a/testing/test_zdistutils.py b/testing/test_zdistutils.py
--- a/testing/test_zdistutils.py
+++ b/testing/test_zdistutils.py
@@ -164,7 +164,8 @@
         assert lib.sin(12.3) == math.sin(12.3)
         v = ffi.verifier
         ext = v.get_extension()
-        assert 'distutils.extension.Extension' in str(ext.__class__)
+        assert 'distutils.extension.Extension' in str(ext.__class__) or \
+               'setuptools.extension.Extension' in str(ext.__class__)
         assert ext.sources == [maybe_relative_path(v.sourcefilename)]
         assert ext.name == v.get_module_name()
         assert ext.define_macros == [('TEST_EXTENSION_OBJECT', '1')]
@@ -193,7 +194,8 @@
         assert lib.test1eoes(7.0) == 42.0
         v = ffi.verifier
         ext = v.get_extension()
-        assert 'distutils.extension.Extension' in str(ext.__class__)
+        assert 'distutils.extension.Extension' in str(ext.__class__) or \
+               'setuptools.extension.Extension' in str(ext.__class__)
         assert ext.sources == [maybe_relative_path(v.sourcefilename),
                                extra_source]
         assert ext.name == v.get_module_name()
diff --git a/testing/test_zintegration.py b/testing/test_zintegration.py
--- a/testing/test_zintegration.py
+++ b/testing/test_zintegration.py
@@ -3,6 +3,9 @@
 import subprocess
 from testing.udir import udir
 
+if sys.platform == 'win32':
+    py.test.skip('snippets do not run on win32')
+
 def create_venv(name):
     tmpdir = udir.join(name)
     try:
@@ -12,6 +15,23 @@
     except OSError as e:
         py.test.skip("Cannot execute virtualenv: %s" % (e,))
 
+    try:
+        deepcopy = os.symlink
+    except:
+        import shutil, errno
+        def deepcopy(src, dst):
+            try:
+                shutil.copytree(src, dst)
+            except OSError as e:
+                if e.errno in (errno.ENOTDIR, errno.EINVAL):
+                    shutil.copy(src, dst)
+                else:
+                    print('got errno')
+                    print(e.errno)
+                    print('not')
+                    print(errno.ENOTDIR)
+                    raise
+
     site_packages = None
     for dirpath, dirnames, filenames in os.walk(str(tmpdir)):
         if os.path.basename(dirpath) == 'site-packages':
@@ -31,7 +51,7 @@
                 modules += ('ply',)   # needed for older versions of pycparser
         for module in modules:
             target = imp.find_module(module)[1]
-            os.symlink(target, os.path.join(site_packages,
+            deepcopy(target, os.path.join(site_packages,
                                             os.path.basename(target)))
     return tmpdir
 
@@ -50,7 +70,11 @@
     python_f.write(py.code.Source(python_snippet))
     try:
         os.chdir(str(SNIPPET_DIR.join(dirname)))
-        vp = str(venv_dir.join('bin/python'))
+        if os.name == 'nt':
+            bindir = 'Scripts'
+        else:
+            bindir = 'bin'
+        vp = str(venv_dir.join(bindir).join('python'))
         subprocess.check_call((vp, 'setup.py', 'clean'))
         subprocess.check_call((vp, 'setup.py', 'install'))
         subprocess.check_call((vp, str(python_f)))
_______________________________________________
pypy-commit mailing list
pypy-commit@python.org
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to