diff options
author | Charles Harris <charlesr.harris@gmail.com> | 2018-03-15 09:40:40 -0600 |
---|---|---|
committer | Charles Harris <charlesr.harris@gmail.com> | 2018-03-19 10:54:36 -0600 |
commit | 7d2f3a63577ab9c40999175f96c6571c39f60ad9 (patch) | |
tree | 5ee0464fdc6116b92923cc4396d3d53afb9b70b4 | |
parent | dce7f20e95e6bd3fc07517c0b2daf3942a34ddf7 (diff) | |
download | python-numpy-7d2f3a63577ab9c40999175f96c6571c39f60ad9.tar.gz python-numpy-7d2f3a63577ab9c40999175f96c6571c39f60ad9.tar.bz2 python-numpy-7d2f3a63577ab9c40999175f96c6571c39f60ad9.zip |
MAINT: Fix Python 3 deprecated C-API use
The PyObject_AsWriteBuffer and PyObject_AsReadBuffer functions are
deprecated in Python 3. Replace them with the Py_buffer based
replacements. Much of that was done prior to this patch, but some uses
were missed.
-rw-r--r-- | numpy/core/src/multiarray/arraytypes.c.src | 19 | ||||
-rw-r--r-- | numpy/core/src/multiarray/common.c | 16 | ||||
-rw-r--r-- | numpy/core/src/multiarray/conversion_utils.c | 12 | ||||
-rw-r--r-- | numpy/core/src/multiarray/ctors.c | 62 | ||||
-rw-r--r-- | numpy/core/src/multiarray/getset.c | 50 | ||||
-rw-r--r-- | numpy/core/src/multiarray/methods.c | 4 | ||||
-rw-r--r-- | numpy/core/src/multiarray/scalartypes.c.src | 24 |
7 files changed, 164 insertions, 23 deletions
diff --git a/numpy/core/src/multiarray/arraytypes.c.src b/numpy/core/src/multiarray/arraytypes.c.src index e8aa19416..5e6804a5c 100644 --- a/numpy/core/src/multiarray/arraytypes.c.src +++ b/numpy/core/src/multiarray/arraytypes.c.src @@ -998,11 +998,25 @@ VOID_setitem(PyObject *op, void *input, void *vap) * undiscerning case: It interprets any object as a buffer * and reads as many bytes as possible, padding with 0. */ +#if defined(NPY_PY3K) + { + Py_buffer view; + + if (PyObject_GetBuffer(op, &view, PyBUF_SIMPLE) < 0) { + return -1; + } + memcpy(ip, view.buf, PyArray_MIN(view.len, itemsize)); + if (itemsize > view.len) { + memset(ip + view.len, 0, itemsize - view.len); + } + PyBuffer_Release(&view); + } +#else { const void *buffer; Py_ssize_t buflen; - res = PyObject_AsReadBuffer(op, &buffer, &buflen); - if (res == -1) { + + if (PyObject_AsReadBuffer(op, &buffer, &buflen) < 0) { return -1; } memcpy(ip, buffer, PyArray_MIN(buflen, itemsize)); @@ -1010,6 +1024,7 @@ VOID_setitem(PyObject *op, void *input, void *vap) memset(ip + buflen, 0, itemsize - buflen); } } +#endif return 0; } diff --git a/numpy/core/src/multiarray/common.c b/numpy/core/src/multiarray/common.c index 10efdc4c8..f191f8db4 100644 --- a/numpy/core/src/multiarray/common.c +++ b/numpy/core/src/multiarray/common.c @@ -305,7 +305,8 @@ PyArray_DTypeFromObjectHelper(PyObject *obj, int maxdims, memset(&buffer_view, 0, sizeof(Py_buffer)); if (PyObject_GetBuffer(obj, &buffer_view, PyBUF_FORMAT|PyBUF_STRIDES) == 0 || - PyObject_GetBuffer(obj, &buffer_view, PyBUF_FORMAT) == 0) { + PyObject_GetBuffer(obj, &buffer_view, + PyBUF_FORMAT|PyBUF_SIMPLE) == 0) { PyErr_Clear(); dtype = _descriptor_from_pep3118_format(buffer_view.format); @@ -633,8 +634,12 @@ NPY_NO_EXPORT npy_bool _IsWriteable(PyArrayObject *ap) { PyObject *base=PyArray_BASE(ap); +#if defined(NPY_PY3K) + Py_buffer view; +#else void *dummy; Py_ssize_t n; +#endif /* If we own our own data, then no-problem */ if ((base == NULL) || (PyArray_FLAGS(ap) & NPY_ARRAY_OWNDATA)) { @@ -668,9 +673,18 @@ _IsWriteable(PyArrayObject *ap) if (PyString_Check(base)) { return NPY_TRUE; } +#if defined(NPY_PY3K) + if (PyObject_GetBuffer(base, &view, PyBUF_WRITABLE|PyBUF_SIMPLE) < 0) { + PyErr_Clear(); + return NPY_FALSE; + } + PyBuffer_Release(&view); +#else if (PyObject_AsWriteBuffer(base, &dummy, &n) < 0) { + PyErr_Clear(); return NPY_FALSE; } +#endif return NPY_TRUE; } diff --git a/numpy/core/src/multiarray/conversion_utils.c b/numpy/core/src/multiarray/conversion_utils.c index 2bb1cbfc1..b39834266 100644 --- a/numpy/core/src/multiarray/conversion_utils.c +++ b/numpy/core/src/multiarray/conversion_utils.c @@ -165,10 +165,12 @@ PyArray_BufferConverter(PyObject *obj, PyArray_Chunk *buf) } #if defined(NPY_PY3K) - if (PyObject_GetBuffer(obj, &view, PyBUF_ANY_CONTIGUOUS|PyBUF_WRITABLE) != 0) { + if (PyObject_GetBuffer(obj, &view, + PyBUF_ANY_CONTIGUOUS|PyBUF_WRITABLE|PyBUF_SIMPLE) != 0) { PyErr_Clear(); buf->flags &= ~NPY_ARRAY_WRITEABLE; - if (PyObject_GetBuffer(obj, &view, PyBUF_ANY_CONTIGUOUS) != 0) { + if (PyObject_GetBuffer(obj, &view, + PyBUF_ANY_CONTIGUOUS|PyBUF_SIMPLE) != 0) { return NPY_FAIL; } } @@ -177,8 +179,10 @@ PyArray_BufferConverter(PyObject *obj, PyArray_Chunk *buf) buf->len = (npy_intp) view.len; /* - * XXX: PyObject_AsWriteBuffer does also this, but it is unsafe, as there is - * no strict guarantee that the buffer sticks around after being released. + * In Python 3 both of the deprecated functions PyObject_AsWriteBuffer and + * PyObject_AsReadBuffer that this code replaces release the buffer. It is + * up to the object that supplies the buffer to guarantee that the buffer + * sticks around after the release. */ PyBuffer_Release(&view); diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index 3d6b161b1..0eba077da 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -729,13 +729,16 @@ discover_dimensions(PyObject *obj, int *maxndim, npy_intp *d, int check_it, /* PEP 3118 buffer interface */ if (PyObject_CheckBuffer(obj) == 1) { memset(&buffer_view, 0, sizeof(Py_buffer)); - if (PyObject_GetBuffer(obj, &buffer_view, PyBUF_STRIDES) == 0 || - PyObject_GetBuffer(obj, &buffer_view, PyBUF_ND) == 0) { + if (PyObject_GetBuffer(obj, &buffer_view, + PyBUF_STRIDES|PyBUF_SIMPLE) == 0 || + PyObject_GetBuffer(obj, &buffer_view, + PyBUF_ND|PyBUF_SIMPLE) == 0) { int nd = buffer_view.ndim; + if (nd < *maxndim) { *maxndim = nd; } - for (i=0; i<*maxndim; i++) { + for (i = 0; i < *maxndim; i++) { d[i] = buffer_view.shape[i]; } PyBuffer_Release(&buffer_view); @@ -756,6 +759,7 @@ discover_dimensions(PyObject *obj, int *maxndim, npy_intp *d, int check_it, e = PyArray_LookupSpecial_OnInstance(obj, "__array_struct__"); if (e != NULL) { int nd = -1; + if (NpyCapsule_Check(e)) { PyArrayInterface *inter; inter = (PyArrayInterface *)NpyCapsule_AsVoidPtr(e); @@ -2187,7 +2191,11 @@ PyArray_FromInterface(PyObject *origin) PyArrayObject *ret; PyArray_Descr *dtype = NULL; char *data = NULL; +#if defined(NPY_PY3K) + Py_buffer view; +#else Py_ssize_t buffer_len; +#endif int res, i, n; npy_intp dims[NPY_MAXDIMS], strides[NPY_MAXDIMS]; int dataflags = NPY_ARRAY_BEHAVED; @@ -2217,7 +2225,7 @@ PyArray_FromInterface(PyObject *origin) if (PyUnicode_Check(attr)) { PyObject *tmp = PyUnicode_AsASCIIString(attr); if (tmp == NULL) { - goto fail; + goto fail; } attr = tmp; } @@ -2251,7 +2259,7 @@ PyArray_FromInterface(PyObject *origin) dtype = new_dtype; } } - + #if defined(NPY_PY3K) Py_DECREF(attr); /* Pairs with the unicode handling above */ #endif @@ -2335,6 +2343,25 @@ PyArray_FromInterface(PyObject *origin) else { base = origin; } +#if defined(NPY_PY3K) + if (PyObject_GetBuffer(base, &view, + PyBUF_WRITABLE|PyBUF_SIMPLE) < 0) { + PyErr_Clear(); + if (PyObject_GetBuffer(base, &view, + PyBUF_SIMPLE) < 0) { + goto fail; + } + dataflags &= ~NPY_ARRAY_WRITEABLE; + } + data = (char *)view.buf; + /* + * In Python 3 both of the deprecated functions PyObject_AsWriteBuffer and + * PyObject_AsReadBuffer that this code replaces release the buffer. It is + * up to the object that supplies the buffer to guarantee that the buffer + * sticks around after the release. + */ + PyBuffer_Release(&view); +#else res = PyObject_AsWriteBuffer(base, (void **)&data, &buffer_len); if (res < 0) { PyErr_Clear(); @@ -2345,6 +2372,7 @@ PyArray_FromInterface(PyObject *origin) } dataflags &= ~NPY_ARRAY_WRITEABLE; } +#endif /* Get offset number from interface specification */ attr = PyDict_GetItemString(origin, "offset"); if (attr) { @@ -3480,6 +3508,9 @@ PyArray_FromBuffer(PyObject *buf, PyArray_Descr *type, { PyArrayObject *ret; char *data; +#if defined(NPY_PY3K) + Py_buffer view; +#endif Py_ssize_t ts; npy_intp s, n; int itemsize; @@ -3519,6 +3550,26 @@ PyArray_FromBuffer(PyObject *buf, PyArray_Descr *type, Py_INCREF(buf); } +#if defined(NPY_PY3K) + if (PyObject_GetBuffer(buf, &view, PyBUF_WRITABLE|PyBUF_SIMPLE) < 0) { + writeable = 0; + PyErr_Clear(); + if (PyObject_GetBuffer(buf, &view, PyBUF_SIMPLE) < 0) { + Py_DECREF(buf); + Py_DECREF(type); + return NULL; + } + } + data = (char *)view.buf; + ts = view.len; + /* + * In Python 3 both of the deprecated functions PyObject_AsWriteBuffer and + * PyObject_AsReadBuffer that this code replaces release the buffer. It is + * up to the object that supplies the buffer to guarantee that the buffer + * sticks around after the release. + */ + PyBuffer_Release(&view); +#else if (PyObject_AsWriteBuffer(buf, (void *)&data, &ts) == -1) { writeable = 0; PyErr_Clear(); @@ -3528,6 +3579,7 @@ PyArray_FromBuffer(PyObject *buf, PyArray_Descr *type, return NULL; } } +#endif if ((offset < 0) || (offset > ts)) { PyErr_Format(PyExc_ValueError, diff --git a/numpy/core/src/multiarray/getset.c b/numpy/core/src/multiarray/getset.c index 825363f19..86e6e7a2f 100644 --- a/numpy/core/src/multiarray/getset.c +++ b/numpy/core/src/multiarray/getset.c @@ -106,8 +106,12 @@ array_strides_set(PyArrayObject *self, PyObject *obj) npy_intp offset = 0; npy_intp lower_offset = 0; npy_intp upper_offset = 0; +#if defined(NPY_PY3K) + Py_buffer view; +#else Py_ssize_t buf_len; char *buf; +#endif if (obj == NULL) { PyErr_SetString(PyExc_AttributeError, @@ -132,12 +136,21 @@ array_strides_set(PyArrayObject *self, PyObject *obj) * Get the available memory through the buffer interface on * PyArray_BASE(new) or if that fails from the current new */ - if (PyArray_BASE(new) && PyObject_AsReadBuffer(PyArray_BASE(new), - (const void **)&buf, - &buf_len) >= 0) { +#if defined(NPY_PY3K) + if (PyArray_BASE(new) && + PyObject_GetBuffer(PyArray_BASE(new), &view, PyBUF_SIMPLE) >= 0) { + offset = PyArray_BYTES(self) - (char *)view.buf; + numbytes = view.len + offset; + PyBuffer_Release(&view); + } +#else + if (PyArray_BASE(new) && + PyObject_AsReadBuffer(PyArray_BASE(new), (const void **)&buf, + &buf_len) >= 0) { offset = PyArray_BYTES(self) - buf; numbytes = buf_len + offset; } +#endif else { PyErr_Clear(); offset_bounds_from_strides(PyArray_ITEMSIZE(new), PyArray_NDIM(new), @@ -328,6 +341,9 @@ array_data_set(PyArrayObject *self, PyObject *op) void *buf; Py_ssize_t buf_len; int writeable=1; +#if defined(NPY_PY3K) + Py_buffer view; +#endif /* 2016-19-02, 1.12 */ int ret = DEPRECATE("Assigning the 'data' attribute is an " @@ -342,18 +358,38 @@ array_data_set(PyArrayObject *self, PyObject *op) "Cannot delete array data"); return -1; } +#if defined(NPY_PY3K) + if (PyObject_GetBuffer(op, &view, PyBUF_WRITABLE|PyBUF_SIMPLE) < 0) { + writeable = 0; + PyErr_Clear(); + if (PyObject_GetBuffer(op, &view, PyBUF_SIMPLE) < 0) { + return -1; + } + } + buf = view.buf; + buf_len = view.len; + /* + * In Python 3 both of the deprecated functions PyObject_AsWriteBuffer and + * PyObject_AsReadBuffer that this code replaces release the buffer. It is + * up to the object that supplies the buffer to guarantee that the buffer + * sticks around after the release. + */ + PyBuffer_Release(&view); +#else if (PyObject_AsWriteBuffer(op, &buf, &buf_len) < 0) { + PyErr_Clear(); writeable = 0; if (PyObject_AsReadBuffer(op, (const void **)&buf, &buf_len) < 0) { + PyErr_Clear(); PyErr_SetString(PyExc_AttributeError, - "object does not have single-segment " \ - "buffer interface"); + "object does not have single-segment buffer interface"); return -1; } } +#endif if (!PyArray_ISONESEGMENT(self)) { - PyErr_SetString(PyExc_AttributeError, "cannot set single-" \ - "segment buffer for discontiguous array"); + PyErr_SetString(PyExc_AttributeError, + "cannot set single-segment buffer for discontiguous array"); return -1; } if (PyArray_NBYTES(self) > buf_len) { diff --git a/numpy/core/src/multiarray/methods.c b/numpy/core/src/multiarray/methods.c index cd88ab76b..004af8a70 100644 --- a/numpy/core/src/multiarray/methods.c +++ b/numpy/core/src/multiarray/methods.c @@ -2305,7 +2305,7 @@ array_setflags(PyArrayObject *self, PyObject *args, PyObject *kwds) } else { PyErr_SetString(PyExc_ValueError, - "cannot set aligned flag of mis-"\ + "cannot set aligned flag of mis-" "aligned array to True"); return NULL; } @@ -2315,7 +2315,7 @@ array_setflags(PyArrayObject *self, PyObject *args, PyObject *kwds) if (PyObject_IsTrue(uic)) { fa->flags = flagback; PyErr_SetString(PyExc_ValueError, - "cannot set WRITEBACKIFCOPY " \ + "cannot set WRITEBACKIFCOPY " "flag to True"); return NULL; } diff --git a/numpy/core/src/multiarray/scalartypes.c.src b/numpy/core/src/multiarray/scalartypes.c.src index ee83206de..9ea26e5e9 100644 --- a/numpy/core/src/multiarray/scalartypes.c.src +++ b/numpy/core/src/multiarray/scalartypes.c.src @@ -1842,6 +1842,9 @@ static PyObject * gentype_reduce(PyObject *self, PyObject *NPY_UNUSED(args)) { PyObject *ret = NULL, *obj = NULL, *mod = NULL; +#if defined(NPY_PY3K) + Py_buffer view; +#endif const char *buffer; Py_ssize_t buflen; @@ -1850,18 +1853,35 @@ gentype_reduce(PyObject *self, PyObject *NPY_UNUSED(args)) if (ret == NULL) { return NULL; } + #if defined(NPY_PY3K) if (PyArray_IsScalar(self, Unicode)) { /* Unicode on Python 3 does not expose the buffer interface */ buffer = PyUnicode_AS_DATA(self); buflen = PyUnicode_GET_DATA_SIZE(self); } - else -#endif + else if (PyObject_GetBuffer(self, &view, PyBUF_SIMPLE) >= 0) { + buffer = view.buf; + buflen = view.len; + /* + * In Python 3 both of the deprecated functions PyObject_AsWriteBuffer and + * PyObject_AsReadBuffer that this code replaces release the buffer. It is + * up to the object that supplies the buffer to guarantee that the buffer + * sticks around after the release. + */ + PyBuffer_Release(&view); + } + else { + Py_DECREF(ret); + return NULL; + } +#else if (PyObject_AsReadBuffer(self, (const void **)&buffer, &buflen)<0) { Py_DECREF(ret); return NULL; } +#endif + mod = PyImport_ImportModule("numpy.core.multiarray"); if (mod == NULL) { return NULL; |