diff options
author | Matti Picus <matti.picus@gmail.com> | 2023-04-27 18:13:21 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-04-27 18:13:21 +0300 |
commit | 4d5e600b799c68fda9c2f06e37fcb3b8af3b18ab (patch) | |
tree | 0264de15f20e7afaa59fc4a299477a072b1589a7 /numpy/core/src | |
parent | 6d34e34e7bc0dad1722958f00f3767d707c1849f (diff) | |
parent | 1d4f1ac67f8b7fca87fc0d3b91270f842f1f9d10 (diff) | |
download | numpy-4d5e600b799c68fda9c2f06e37fcb3b8af3b18ab.tar.gz |
Merge pull request #23666 from seberg/subarray-cleanup
DEP,BUG: Finalize subarray dtype FutureWarning and fix its assignment
Diffstat (limited to 'numpy/core/src')
-rw-r--r-- | numpy/core/src/multiarray/arrayobject.c | 4 | ||||
-rw-r--r-- | numpy/core/src/multiarray/convert.c | 2 | ||||
-rw-r--r-- | numpy/core/src/multiarray/ctors.c | 331 | ||||
-rw-r--r-- | numpy/core/src/multiarray/ctors.h | 21 | ||||
-rw-r--r-- | numpy/core/src/multiarray/dtype_transfer.c | 6 | ||||
-rw-r--r-- | numpy/core/src/multiarray/einsum.c.src | 3 | ||||
-rw-r--r-- | numpy/core/src/multiarray/getset.c | 2 | ||||
-rw-r--r-- | numpy/core/src/multiarray/mapping.c | 10 | ||||
-rw-r--r-- | numpy/core/src/multiarray/methods.c | 35 | ||||
-rw-r--r-- | numpy/core/src/multiarray/multiarraymodule.c | 4 | ||||
-rw-r--r-- | numpy/core/src/multiarray/shape.c | 2 | ||||
-rw-r--r-- | numpy/core/src/umath/ufunc_object.c | 8 |
12 files changed, 122 insertions, 306 deletions
diff --git a/numpy/core/src/multiarray/arrayobject.c b/numpy/core/src/multiarray/arrayobject.c index 0434e8676..46c4d90c9 100644 --- a/numpy/core/src/multiarray/arrayobject.c +++ b/numpy/core/src/multiarray/arrayobject.c @@ -1223,7 +1223,7 @@ array_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) (int)dims.len, dims.ptr, strides.ptr, NULL, is_f_order, NULL, NULL, - 0, 1); + _NPY_ARRAY_ALLOW_EMPTY_STRING); if (ret == NULL) { descr = NULL; goto fail; @@ -1260,7 +1260,7 @@ array_new(PyTypeObject *subtype, PyObject *args, PyObject *kwds) subtype, descr, dims.len, dims.ptr, strides.ptr, offset + (char *)buffer.ptr, buffer.flags, NULL, buffer.base, - 0, 1); + _NPY_ARRAY_ALLOW_EMPTY_STRING); if (ret == NULL) { descr = NULL; goto fail; diff --git a/numpy/core/src/multiarray/convert.c b/numpy/core/src/multiarray/convert.c index 9e0c9fb60..e8b880a43 100644 --- a/numpy/core/src/multiarray/convert.c +++ b/numpy/core/src/multiarray/convert.c @@ -509,7 +509,7 @@ PyArray_View(PyArrayObject *self, PyArray_Descr *type, PyTypeObject *pytype) PyArray_NDIM(self), PyArray_DIMS(self), PyArray_STRIDES(self), PyArray_DATA(self), flags, (PyObject *)self, (PyObject *)self, - 0, 1); + _NPY_ARRAY_ENSURE_DTYPE_IDENTITY); if (ret == NULL) { Py_XDECREF(type); return NULL; diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c index 79a1905a7..3c5b047c3 100644 --- a/numpy/core/src/multiarray/ctors.c +++ b/numpy/core/src/multiarray/ctors.c @@ -628,8 +628,7 @@ NPY_NO_EXPORT PyObject * PyArray_NewFromDescr_int( PyTypeObject *subtype, PyArray_Descr *descr, int nd, npy_intp const *dims, npy_intp const *strides, void *data, - int flags, PyObject *obj, PyObject *base, int zeroed, - int allow_emptystring) + int flags, PyObject *obj, PyObject *base, _NPY_CREATION_FLAGS cflags) { PyArrayObject_fields *fa; npy_intp nbytes; @@ -644,45 +643,54 @@ PyArray_NewFromDescr_int( return NULL; } - if (descr->subarray) { - PyObject *ret; - npy_intp newdims[2*NPY_MAXDIMS]; - npy_intp *newstrides = NULL; - memcpy(newdims, dims, nd*sizeof(npy_intp)); - if (strides) { - newstrides = newdims + NPY_MAXDIMS; - memcpy(newstrides, strides, nd*sizeof(npy_intp)); - } - nd =_update_descr_and_dimensions(&descr, newdims, - newstrides, nd); - ret = PyArray_NewFromDescr_int( - subtype, descr, - nd, newdims, newstrides, data, - flags, obj, base, - zeroed, allow_emptystring); - return ret; - } - - /* Check datatype element size */ nbytes = descr->elsize; - if (PyDataType_ISUNSIZED(descr)) { - if (!PyDataType_ISFLEXIBLE(descr) && - NPY_DT_is_legacy(NPY_DTYPE(descr))) { - PyErr_SetString(PyExc_TypeError, "Empty data-type"); - Py_DECREF(descr); - return NULL; - } - else if (PyDataType_ISSTRING(descr) && !allow_emptystring && - data == NULL) { - PyArray_DESCR_REPLACE(descr); - if (descr == NULL) { + /* + * Unless explicitly asked not to, we do replace dtypes in some cases. + * This mainly means that we never create arrays with a subarray dtype + * (unless for internal use when requested). And neither do we create + * S0/U0 arrays in most cases (unless data == NULL so this is probably + * a view where growing the dtype would be presumable wrong). + */ + if (!(cflags & _NPY_ARRAY_ENSURE_DTYPE_IDENTITY)) { + if (descr->subarray) { + PyObject *ret; + npy_intp newdims[2*NPY_MAXDIMS]; + npy_intp *newstrides = NULL; + memcpy(newdims, dims, nd*sizeof(npy_intp)); + if (strides) { + newstrides = newdims + NPY_MAXDIMS; + memcpy(newstrides, strides, nd*sizeof(npy_intp)); + } + nd =_update_descr_and_dimensions(&descr, newdims, + newstrides, nd); + ret = PyArray_NewFromDescr_int( + subtype, descr, + nd, newdims, newstrides, data, + flags, obj, base, cflags); + return ret; + } + + /* Check datatype element size */ + if (PyDataType_ISUNSIZED(descr)) { + if (!PyDataType_ISFLEXIBLE(descr) && + NPY_DT_is_legacy(NPY_DTYPE(descr))) { + PyErr_SetString(PyExc_TypeError, "Empty data-type"); + Py_DECREF(descr); return NULL; } - if (descr->type_num == NPY_STRING) { - nbytes = descr->elsize = 1; - } - else { - nbytes = descr->elsize = sizeof(npy_ucs4); + else if (PyDataType_ISSTRING(descr) + && !(cflags & _NPY_ARRAY_ALLOW_EMPTY_STRING) + && data == NULL) { + PyArray_DESCR_REPLACE(descr); + if (descr == NULL) { + return NULL; + } + if (descr->type_num == NPY_STRING) { + nbytes = descr->elsize = 1; + } + else { + nbytes = descr->elsize = sizeof(npy_ucs4); + } } } } @@ -811,8 +819,9 @@ PyArray_NewFromDescr_int( * with malloc and let the zero-filling loop fill the array buffer * with valid zero values for the dtype. */ - int use_calloc = (PyDataType_FLAGCHK(descr, NPY_NEEDS_INIT) || - (zeroed && (fill_zero_info.func == NULL))); + int use_calloc = ( + PyDataType_FLAGCHK(descr, NPY_NEEDS_INIT) || + ((cflags & _NPY_ARRAY_ZEROED) && (fill_zero_info.func == NULL))); /* Store the handler in case the default is modified */ fa->mem_handler = PyDataMem_GetHandler(); @@ -846,7 +855,8 @@ PyArray_NewFromDescr_int( /* * If the array needs special dtype-specific zero-filling logic, do that */ - if (NPY_UNLIKELY(zeroed && (fill_zero_info.func != NULL))) { + if (NPY_UNLIKELY((cflags & _NPY_ARRAY_ZEROED) + && (fill_zero_info.func != NULL))) { npy_intp size = PyArray_MultiplyList(fa->dimensions, fa->nd); if (fill_zero_info.func( NULL, descr, data, size, descr->elsize, @@ -1001,7 +1011,7 @@ PyArray_NewFromDescrAndBase( { return PyArray_NewFromDescr_int(subtype, descr, nd, dims, strides, data, - flags, obj, base, 0, 0); + flags, obj, base, 0); } /* @@ -1484,160 +1494,6 @@ PyArray_GetArrayParamsFromObject(PyObject *NPY_UNUSED(op), } -/* - * This function is a legacy implementation to retain subarray dtype - * behaviour in array coercion. The behaviour here makes sense if tuples - * of matching dimensionality are being coerced. Due to the difficulty - * that the result is ill-defined for lists of array-likes, this is deprecated. - * - * WARNING: Do not use this function, it exists purely to support a deprecated - * code path. - */ -static int -setArrayFromSequence(PyArrayObject *a, PyObject *s, - int dim, PyArrayObject * dst) -{ - Py_ssize_t i, slen; - int res = -1; - - /* first recursion, view equal destination */ - if (dst == NULL) - dst = a; - - /* - * This code is to ensure that the sequence access below will - * return a lower-dimensional sequence. - */ - - /* INCREF on entry DECREF on exit */ - Py_INCREF(s); - - PyObject *seq = NULL; - - if (PyArray_Check(s)) { - if (!(PyArray_CheckExact(s))) { - /* - * make sure a base-class array is used so that the dimensionality - * reduction assumption is correct. - */ - /* This will DECREF(s) if replaced */ - s = PyArray_EnsureArray(s); - if (s == NULL) { - goto fail; - } - } - - /* dst points to correct array subsection */ - if (PyArray_CopyInto(dst, (PyArrayObject *)s) < 0) { - goto fail; - } - - Py_DECREF(s); - return 0; - } - - if (dim > PyArray_NDIM(a)) { - PyErr_Format(PyExc_ValueError, - "setArrayFromSequence: sequence/array dimensions mismatch."); - goto fail; - } - - /* Try __array__ before using s as a sequence */ - PyObject *tmp = _array_from_array_like(s, NULL, 0, NULL, 0); - if (tmp == NULL) { - goto fail; - } - else if (tmp == Py_NotImplemented) { - Py_DECREF(tmp); - } - else { - int r = PyArray_CopyInto(dst, (PyArrayObject *)tmp); - Py_DECREF(tmp); - if (r < 0) { - goto fail; - } - Py_DECREF(s); - return 0; - } - - seq = PySequence_Fast(s, "Could not convert object to sequence"); - if (seq == NULL) { - goto fail; - } - slen = PySequence_Fast_GET_SIZE(seq); - - /* - * Either the dimensions match, or the sequence has length 1 and can - * be broadcast to the destination. - */ - if (slen != PyArray_DIMS(a)[dim] && slen != 1) { - PyErr_Format(PyExc_ValueError, - "cannot copy sequence with size %zd to array axis " - "with dimension %" NPY_INTP_FMT, slen, PyArray_DIMS(a)[dim]); - goto fail; - } - - /* Broadcast the one element from the sequence to all the outputs */ - if (slen == 1) { - PyObject *o = PySequence_Fast_GET_ITEM(seq, 0); - npy_intp alen = PyArray_DIM(a, dim); - - for (i = 0; i < alen; i++) { - if ((PyArray_NDIM(a) - dim) > 1) { - PyArrayObject * tmp = - (PyArrayObject *)array_item_asarray(dst, i); - if (tmp == NULL) { - goto fail; - } - - res = setArrayFromSequence(a, o, dim+1, tmp); - Py_DECREF(tmp); - } - else { - char * b = (PyArray_BYTES(dst) + i * PyArray_STRIDES(dst)[0]); - res = PyArray_SETITEM(dst, b, o); - } - if (res < 0) { - goto fail; - } - } - } - /* Copy element by element */ - else { - for (i = 0; i < slen; i++) { - PyObject * o = PySequence_Fast_GET_ITEM(seq, i); - if ((PyArray_NDIM(a) - dim) > 1) { - PyArrayObject * tmp = - (PyArrayObject *)array_item_asarray(dst, i); - if (tmp == NULL) { - goto fail; - } - - res = setArrayFromSequence(a, o, dim+1, tmp); - Py_DECREF(tmp); - } - else { - char * b = (PyArray_BYTES(dst) + i * PyArray_STRIDES(dst)[0]); - res = PyArray_SETITEM(dst, b, o); - } - if (res < 0) { - goto fail; - } - } - } - - Py_DECREF(seq); - Py_DECREF(s); - return 0; - - fail: - Py_XDECREF(seq); - Py_DECREF(s); - return res; -} - - - /*NUMPY_API * Does not check for NPY_ARRAY_ENSURECOPY and NPY_ARRAY_NOTSWAPPED in flags * Steals a reference to newtype --- which can be NULL @@ -1700,70 +1556,6 @@ PyArray_FromAny_int(PyObject *op, PyArray_Descr *in_descr, return NULL; } - if (NPY_UNLIKELY(in_descr != NULL && PyDataType_HASSUBARRAY(dtype))) { - /* - * When a subarray dtype was passed in, its dimensions are appended - * to the array dimension (causing a dimension mismatch). - * There is a problem with that, because if we coerce from non-arrays - * we do this correctly by element (as defined by tuples), but for - * arrays we first append the dimensions and then assign to the base - * dtype and then assign which causes the problem. - * - * Thus, we check if there is an array included, in that case we - * give a FutureWarning. - * When the warning is removed, PyArray_Pack will have to ensure - * that it does not append the dimensions when creating the subarrays - * to assign `arr[0] = obj[0]`. - */ - int includes_array = 0; - if (cache != NULL) { - /* This is not ideal, but it is a pretty special case */ - coercion_cache_obj *next = cache; - while (next != NULL) { - if (!next->sequence) { - includes_array = 1; - break; - } - next = next->next; - } - } - if (includes_array) { - npy_free_coercion_cache(cache); - - ret = (PyArrayObject *) PyArray_NewFromDescr( - &PyArray_Type, dtype, ndim, dims, NULL, NULL, - flags & NPY_ARRAY_F_CONTIGUOUS, NULL); - if (ret == NULL) { - return NULL; - } - assert(PyArray_NDIM(ret) != ndim); - - /* NumPy 1.20, 2020-10-01 */ - if (DEPRECATE_FUTUREWARNING( - "creating an array with a subarray dtype will behave " - "differently when the `np.array()` (or `asarray`, etc.) " - "call includes an array or array object.\n" - "If you are converting a single array or a list of arrays," - "you can opt-in to the future behaviour using:\n" - " np.array(arr, dtype=np.dtype(['f', dtype]))['f']\n" - " np.array([arr1, arr2], dtype=np.dtype(['f', dtype]))['f']\n" - "\n" - "By including a new field and indexing it after the " - "conversion.\n" - "This may lead to a different result or to current failures " - "succeeding. (FutureWarning since NumPy 1.20)") < 0) { - Py_DECREF(ret); - return NULL; - } - - if (setArrayFromSequence(ret, op, 0, NULL) < 0) { - Py_DECREF(ret); - return NULL; - } - return (PyObject *)ret; - } - } - if (dtype == NULL) { dtype = PyArray_DescrFromType(NPY_DEFAULT_TYPE); } @@ -2127,13 +1919,26 @@ PyArray_FromArray(PyArrayObject *arr, PyArray_Descr *newtype, int flags) if ((flags & NPY_ARRAY_ENSUREARRAY)) { subok = 0; } + Py_INCREF(newtype); ret = (PyArrayObject *)PyArray_NewLikeArray(arr, order, newtype, subok); if (ret == NULL) { + Py_DECREF(newtype); return NULL; } - if (PyArray_CopyInto(ret, arr) < 0) { + int actual_ndim = PyArray_NDIM(ret); + PyArray_Descr *actual_dtype = PyArray_DESCR(ret); + ((PyArrayObject_fields *)ret)->nd = PyArray_NDIM(arr); + ((PyArrayObject_fields *)ret)->descr = newtype; + + int success = PyArray_CopyInto(ret, arr); + + Py_DECREF(newtype); + ((PyArrayObject_fields *)ret)->nd = actual_ndim; + ((PyArrayObject_fields *)ret)->descr = actual_dtype; + + if (success < 0) { Py_DECREF(ret); return NULL; } @@ -3052,7 +2857,7 @@ PyArray_Zeros(int nd, npy_intp const *dims, PyArray_Descr *type, int is_f_order) &PyArray_Type, type, nd, dims, NULL, NULL, is_f_order, NULL, NULL, - 1, 0); + _NPY_ARRAY_ZEROED); if (ret == NULL) { return NULL; @@ -3706,7 +3511,7 @@ PyArray_FromFile(FILE *fp, PyArray_Descr *dtype, npy_intp num, char *sep) &PyArray_Type, dtype, 1, &num, NULL, NULL, 0, NULL, NULL, - 0, 1); + _NPY_ARRAY_ALLOW_EMPTY_STRING); } if ((sep == NULL) || (strlen(sep) == 0)) { ret = array_fromfile_binary(fp, dtype, num, &nread); diff --git a/numpy/core/src/multiarray/ctors.h b/numpy/core/src/multiarray/ctors.h index 22020e26a..a876ab2c0 100644 --- a/numpy/core/src/multiarray/ctors.h +++ b/numpy/core/src/multiarray/ctors.h @@ -13,12 +13,29 @@ PyArray_NewFromDescrAndBase( npy_intp const *dims, npy_intp const *strides, void *data, int flags, PyObject *obj, PyObject *base); + +/* Private options for NewFromDescriptor */ +typedef enum { + /* + * Indicate the the array should be zeroed, we may use calloc to do so + * (otherwise much like ). + */ + _NPY_ARRAY_ZEROED = 1 << 0, + /* Whether to allow empty strings (implied by ensure dtype identity) */ + _NPY_ARRAY_ALLOW_EMPTY_STRING = 1 << 1, + /* + * If we take a view into an existing array and use its dtype, then that + * dtype must be preserved (for example for subarray and S0, but also + * possibly for future dtypes that store more metadata). + */ + _NPY_ARRAY_ENSURE_DTYPE_IDENTITY = 1 << 2, +} _NPY_CREATION_FLAGS; + NPY_NO_EXPORT PyObject * PyArray_NewFromDescr_int( PyTypeObject *subtype, PyArray_Descr *descr, int nd, npy_intp const *dims, npy_intp const *strides, void *data, - int flags, PyObject *obj, PyObject *base, int zeroed, - int allow_emptystring); + int flags, PyObject *obj, PyObject *base, _NPY_CREATION_FLAGS cflags); NPY_NO_EXPORT PyObject * PyArray_NewLikeArrayWithShape( diff --git a/numpy/core/src/multiarray/dtype_transfer.c b/numpy/core/src/multiarray/dtype_transfer.c index 9e77d456d..f79662040 100644 --- a/numpy/core/src/multiarray/dtype_transfer.c +++ b/numpy/core/src/multiarray/dtype_transfer.c @@ -567,7 +567,7 @@ wrap_copy_swap_function( &PyArray_Type, dtype, 1, &shape, NULL, NULL, 0, NULL, NULL, - 0, 1); + _NPY_ARRAY_ENSURE_DTYPE_IDENTITY); if (data->arr == NULL) { PyMem_Free(data); return NPY_FAIL; @@ -1316,7 +1316,7 @@ get_legacy_dtype_cast_function( &PyArray_Type, tmp_dtype, 1, &shape, NULL, NULL, 0, NULL, NULL, - 0, 1); + _NPY_ARRAY_ENSURE_DTYPE_IDENTITY); if (data->aip == NULL) { PyMem_Free(data); return NPY_FAIL; @@ -1343,7 +1343,7 @@ get_legacy_dtype_cast_function( &PyArray_Type, tmp_dtype, 1, &shape, NULL, NULL, 0, NULL, NULL, - 0, 1); + _NPY_ARRAY_ENSURE_DTYPE_IDENTITY); if (data->aop == NULL) { Py_DECREF(data->aip); PyMem_Free(data); diff --git a/numpy/core/src/multiarray/einsum.c.src b/numpy/core/src/multiarray/einsum.c.src index cd1a58982..9f9d41579 100644 --- a/numpy/core/src/multiarray/einsum.c.src +++ b/numpy/core/src/multiarray/einsum.c.src @@ -321,8 +321,7 @@ get_single_op_view(PyArrayObject *op, char *labels, Py_TYPE(op), PyArray_DESCR(op), ndim_output, new_dims, new_strides, PyArray_DATA(op), PyArray_ISWRITEABLE(op) ? NPY_ARRAY_WRITEABLE : 0, - (PyObject *)op, (PyObject *)op, - 0, 0); + (PyObject *)op, (PyObject *)op, 0); if (*ret == NULL) { return -1; diff --git a/numpy/core/src/multiarray/getset.c b/numpy/core/src/multiarray/getset.c index d019acbb5..7022eb231 100644 --- a/numpy/core/src/multiarray/getset.c +++ b/numpy/core/src/multiarray/getset.c @@ -804,7 +804,7 @@ array_imag_get(PyArrayObject *self, void *NPY_UNUSED(ignored)) PyArray_DIMS(self), NULL, NULL, PyArray_ISFORTRAN(self), - (PyObject *)self, NULL, 1, 0); + (PyObject *)self, NULL, _NPY_ARRAY_ZEROED); if (ret == NULL) { return NULL; } diff --git a/numpy/core/src/multiarray/mapping.c b/numpy/core/src/multiarray/mapping.c index 3dd488220..b7fcf2ee2 100644 --- a/numpy/core/src/multiarray/mapping.c +++ b/numpy/core/src/multiarray/mapping.c @@ -889,13 +889,13 @@ get_view_from_index(PyArrayObject *self, PyArrayObject **view, /* Create the new view and set the base array */ Py_INCREF(PyArray_DESCR(self)); - *view = (PyArrayObject *)PyArray_NewFromDescrAndBase( + *view = (PyArrayObject *)PyArray_NewFromDescr_int( ensure_array ? &PyArray_Type : Py_TYPE(self), PyArray_DESCR(self), new_dim, new_shape, new_strides, data_ptr, PyArray_FLAGS(self), ensure_array ? NULL : (PyObject *)self, - (PyObject *)self); + (PyObject *)self, _NPY_ARRAY_ENSURE_DTYPE_IDENTITY); if (*view == NULL) { return -1; } @@ -1361,7 +1361,8 @@ _get_field_view(PyArrayObject *arr, PyObject *ind, PyArrayObject **view) PyArray_BYTES(arr) + offset, PyArray_FLAGS(arr), (PyObject *)arr, (PyObject *)arr, - 0, 1); + /* We do not preserve the dtype for a subarray one, only str */ + _NPY_ARRAY_ALLOW_EMPTY_STRING); if (*view == NULL) { return 0; } @@ -1415,7 +1416,8 @@ _get_field_view(PyArrayObject *arr, PyObject *ind, PyArrayObject **view) PyArray_DATA(arr), PyArray_FLAGS(arr), (PyObject *)arr, (PyObject *)arr, - 0, 1); + /* We do not preserve the dtype for a subarray one, only str */ + _NPY_ARRAY_ALLOW_EMPTY_STRING); if (*view == NULL) { return 0; diff --git a/numpy/core/src/multiarray/methods.c b/numpy/core/src/multiarray/methods.c index 3b2e72820..bc3efc295 100644 --- a/numpy/core/src/multiarray/methods.c +++ b/numpy/core/src/multiarray/methods.c @@ -437,7 +437,7 @@ PyArray_GetField(PyArrayObject *self, PyArray_Descr *typed, int offset) PyArray_BYTES(self) + offset, PyArray_FLAGS(self) & ~NPY_ARRAY_F_CONTIGUOUS, (PyObject *)self, (PyObject *)self, - 0, 1); + _NPY_ARRAY_ALLOW_EMPTY_STRING); return ret; } @@ -924,29 +924,28 @@ array_astype(PyArrayObject *self, PyArrayObject *ret; - /* This steals the reference to dtype, so no DECREF of dtype */ + /* This steals the reference to dtype */ + Py_INCREF(dtype); ret = (PyArrayObject *)PyArray_NewLikeArray( self, order, dtype, subok); if (ret == NULL) { + Py_DECREF(dtype); return NULL; } - /* NumPy 1.20, 2020-10-01 */ - if ((PyArray_NDIM(self) != PyArray_NDIM(ret)) && - DEPRECATE_FUTUREWARNING( - "casting an array to a subarray dtype " - "will not use broadcasting in the future, but cast each " - "element to the new dtype and then append the dtype's shape " - "to the new array. You can opt-in to the new behaviour, by " - "additional field to the cast: " - "`arr.astype(np.dtype([('f', dtype)]))['f']`.\n" - "This may lead to a different result or to current failures " - "succeeding. " - "(FutureWarning since NumPy 1.20)") < 0) { - Py_DECREF(ret); - return NULL; - } - if (PyArray_CopyInto(ret, self) < 0) { + /* Decrease the number of dimensions removing subarray ones again */ + int out_ndim = PyArray_NDIM(ret); + PyArray_Descr *out_descr = PyArray_DESCR(ret); + ((PyArrayObject_fields *)ret)->nd = PyArray_NDIM(self); + ((PyArrayObject_fields *)ret)->descr = dtype; + + int success = PyArray_CopyInto(ret, self); + + Py_DECREF(dtype); + ((PyArrayObject_fields *)ret)->nd = out_ndim; + ((PyArrayObject_fields *)ret)->descr = out_descr; + + if (success < 0) { Py_DECREF(ret); return NULL; } diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c index 98ca15ac4..029e41990 100644 --- a/numpy/core/src/multiarray/multiarraymodule.c +++ b/numpy/core/src/multiarray/multiarraymodule.c @@ -494,7 +494,7 @@ PyArray_ConcatenateArrays(int narrays, PyArrayObject **arrays, int axis, /* Allocate the array for the result. This steals the 'dtype' reference. */ ret = (PyArrayObject *)PyArray_NewFromDescr_int( subtype, descr, ndim, shape, strides, NULL, 0, NULL, - NULL, 0, 1); + NULL, _NPY_ARRAY_ALLOW_EMPTY_STRING); if (ret == NULL) { return NULL; } @@ -599,7 +599,7 @@ PyArray_ConcatenateFlattenedArrays(int narrays, PyArrayObject **arrays, /* Allocate the array for the result. This steals the 'dtype' reference. */ ret = (PyArrayObject *)PyArray_NewFromDescr_int( subtype, descr, 1, &shape, &stride, NULL, 0, NULL, - NULL, 0, 1); + NULL, _NPY_ARRAY_ALLOW_EMPTY_STRING); if (ret == NULL) { return NULL; } diff --git a/numpy/core/src/multiarray/shape.c b/numpy/core/src/multiarray/shape.c index 25af43bbc..15b166423 100644 --- a/numpy/core/src/multiarray/shape.c +++ b/numpy/core/src/multiarray/shape.c @@ -285,7 +285,7 @@ PyArray_Newshape(PyArrayObject *self, PyArray_Dims *newdims, Py_TYPE(self), PyArray_DESCR(self), ndim, dimensions, strides, PyArray_DATA(self), flags, (PyObject *)self, (PyObject *)self, - 0, 1); + _NPY_ARRAY_ENSURE_DTYPE_IDENTITY); Py_DECREF(self); return (PyObject *)ret; } diff --git a/numpy/core/src/umath/ufunc_object.c b/numpy/core/src/umath/ufunc_object.c index d4aced05f..39e64decb 100644 --- a/numpy/core/src/umath/ufunc_object.c +++ b/numpy/core/src/umath/ufunc_object.c @@ -6607,16 +6607,10 @@ py_resolve_dtypes_generic(PyUFuncObject *ufunc, npy_bool return_context, Py_INCREF(descr); dummy_arrays[i] = (PyArrayObject *)PyArray_NewFromDescr_int( &PyArray_Type, descr, 0, NULL, NULL, NULL, - 0, NULL, NULL, 0, 1); + 0, NULL, NULL, _NPY_ARRAY_ENSURE_DTYPE_IDENTITY); if (dummy_arrays[i] == NULL) { goto finish; } - if (PyArray_DESCR(dummy_arrays[i]) != descr) { - PyErr_SetString(PyExc_NotImplementedError, - "dtype was replaced during array creation, the dtype is " - "unsupported currently (a subarray dtype?)."); - goto finish; - } DTypes[i] = NPY_DTYPE(descr); Py_INCREF(DTypes[i]); if (!NPY_DT_is_legacy(DTypes[i])) { |