summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorEric Wieser <wieser.eric@gmail.com>2017-07-30 21:48:44 +0100
committerEric Wieser <wieser.eric@gmail.com>2017-07-31 20:00:24 +0100
commit8cc44809fd5c458d9fb27e7851eedc59abfbc7be (patch)
treebd2b4469a2646a6689e9cd2a11094e17cef591fa /numpy
parent2791167653a1b586aa54830cc2ab4f736cbe4f0a (diff)
downloadnumpy-8cc44809fd5c458d9fb27e7851eedc59abfbc7be.tar.gz
MAINT/BUG: Improve error messages for dtype reassigment, fix missing DECREF
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/src/multiarray/getset.c115
1 files changed, 64 insertions, 51 deletions
diff --git a/numpy/core/src/multiarray/getset.c b/numpy/core/src/multiarray/getset.c
index 538256369..2b7d498aa 100644
--- a/numpy/core/src/multiarray/getset.c
+++ b/numpy/core/src/multiarray/getset.c
@@ -438,8 +438,7 @@ array_descr_set(PyArrayObject *self, PyObject *arg)
{
PyArray_Descr *newtype = NULL;
npy_intp newdim;
- int i;
- char *msg = "new type not compatible with array.";
+ int axis;
PyObject *safe;
static PyObject *checkfunc = NULL;
@@ -461,14 +460,13 @@ array_descr_set(PyArrayObject *self, PyObject *arg)
if (_may_have_objects(PyArray_DESCR(self)) || _may_have_objects(newtype)) {
npy_cache_import("numpy.core._internal", "_view_is_safe", &checkfunc);
if (checkfunc == NULL) {
- return -1;
+ goto fail;
}
safe = PyObject_CallFunction(checkfunc, "OO",
PyArray_DESCR(self), newtype);
if (safe == NULL) {
- Py_DECREF(newtype);
- return -1;
+ goto fail;
}
Py_DECREF(safe);
}
@@ -492,58 +490,73 @@ array_descr_set(PyArrayObject *self, PyObject *arg)
}
- if ((newtype->elsize != PyArray_DESCR(self)->elsize) &&
- (PyArray_NDIM(self) == 0 ||
- !PyArray_ISONESEGMENT(self) ||
- PyDataType_HASSUBARRAY(newtype))) {
- goto fail;
- }
-
- /* Deprecate not C contiguous and a dimension changes */
- if (newtype->elsize != PyArray_DESCR(self)->elsize &&
- !PyArray_IS_C_CONTIGUOUS(self)) {
- /* 11/27/2015 1.11.0 */
- if (DEPRECATE("Changing the shape of non-C contiguous array by\n"
- "descriptor assignment is deprecated. To maintain\n"
- "the Fortran contiguity of a multidimensional Fortran\n"
- "array, use 'a.T.view(...).T' instead") < 0) {
- return -1;
+ /* Changing the size of the dtype results in a shape change */
+ if (newtype->elsize != PyArray_DESCR(self)->elsize) {
+ /* forbidden cases */
+ if (PyArray_NDIM(self) == 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "Changing the dtype of a 0d array is only supported "
+ "if the itemsize is unchanged");
+ goto fail;
}
- }
-
- if (PyArray_IS_C_CONTIGUOUS(self)) {
- i = PyArray_NDIM(self) - 1;
- }
- else {
- i = 0;
- }
- if (newtype->elsize < PyArray_DESCR(self)->elsize) {
- /*
- * if it is compatible increase the size of the
- * dimension at end (or at the front for NPY_ARRAY_F_CONTIGUOUS)
- */
- if (PyArray_DESCR(self)->elsize % newtype->elsize != 0) {
+ else if (PyDataType_HASSUBARRAY(newtype)) {
+ PyErr_SetString(PyExc_ValueError,
+ "Changing the dtype to a subarray type is only supported "
+ "if the total itemsize is unchanged");
goto fail;
}
- newdim = PyArray_DESCR(self)->elsize / newtype->elsize;
- PyArray_DIMS(self)[i] *= newdim;
- PyArray_STRIDES(self)[i] = newtype->elsize;
- }
- else if (newtype->elsize > PyArray_DESCR(self)->elsize) {
- /*
- * Determine if last (or first if NPY_ARRAY_F_CONTIGUOUS) dimension
- * is compatible
- */
- newdim = PyArray_DIMS(self)[i] * PyArray_DESCR(self)->elsize;
- if ((newdim % newtype->elsize) != 0) {
+
+ /* determine which axis to resize */
+ if (PyArray_IS_C_CONTIGUOUS(self)) {
+ axis = PyArray_NDIM(self) - 1;
+ }
+ else if (PyArray_IS_F_CONTIGUOUS(self)) {
+ /* 2015-11-27 1.11.0, gh-6747 */
+ if (DEPRECATE(
+ "Changing the shape of an F-contiguous array by "
+ "descriptor assignment is deprecated. To maintain the "
+ "Fortran contiguity of a multidimensional Fortran "
+ "array, use 'a.T.view(...).T' instead") < 0) {
+ goto fail;
+ }
+ axis = 0;
+ }
+ else {
+ /* Don't mention the deprecated F-contiguous support */
+ PyErr_SetString(PyExc_ValueError,
+ "To change to a dtype of a different size, the array must "
+ "be C-contiguous");
goto fail;
}
- PyArray_DIMS(self)[i] = newdim / newtype->elsize;
- PyArray_STRIDES(self)[i] = newtype->elsize;
+
+ if (newtype->elsize < PyArray_DESCR(self)->elsize) {
+ /* if it is compatible, increase the size of the relevant axis */
+ if (PyArray_DESCR(self)->elsize % newtype->elsize != 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "When changing to a smaller dtype, its size must be a "
+ "divisor of the size of original dtype");
+ goto fail;
+ }
+ newdim = PyArray_DESCR(self)->elsize / newtype->elsize;
+ PyArray_DIMS(self)[axis] *= newdim;
+ PyArray_STRIDES(self)[axis] = newtype->elsize;
+ }
+ else if (newtype->elsize > PyArray_DESCR(self)->elsize) {
+ /* if it is compatible, decrease the size of the relevant axis */
+ newdim = PyArray_DIMS(self)[axis] * PyArray_DESCR(self)->elsize;
+ if ((newdim % newtype->elsize) != 0) {
+ PyErr_SetString(PyExc_ValueError,
+ "When changing to a larger dtype, its size must be a "
+ "divisor of the total size in bytes of the last axis "
+ "of the array.");
+ goto fail;
+ }
+ PyArray_DIMS(self)[axis] = newdim / newtype->elsize;
+ PyArray_STRIDES(self)[axis] = newtype->elsize;
+ }
}
- /* fall through -- adjust type*/
- Py_DECREF(PyArray_DESCR(self));
+ /* Viewing as a subarray increases the number of dimensions */
if (PyDataType_HASSUBARRAY(newtype)) {
/*
* create new array object from data and update
@@ -573,12 +586,12 @@ array_descr_set(PyArrayObject *self, PyObject *arg)
Py_DECREF(temp);
}
+ Py_DECREF(PyArray_DESCR(self));
((PyArrayObject_fields *)self)->descr = newtype;
PyArray_UpdateFlags(self, NPY_ARRAY_UPDATE_ALL);
return 0;
fail:
- PyErr_SetString(PyExc_ValueError, msg);
Py_DECREF(newtype);
return -1;
}