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