Author: Armin Rigo <[email protected]>
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
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit