Skip to content

Commit

Permalink
Merge pull request #24128 from charris/backport-24103
Browse files Browse the repository at this point in the history
BUG: Only replace dtype temporarily if dimensions changed
  • Loading branch information
charris authored Jul 6, 2023
2 parents f5012c7 + b36db1c commit 0d36673
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 7 deletions.
12 changes: 8 additions & 4 deletions numpy/core/src/multiarray/ctors.c
Original file line number Diff line number Diff line change
Expand Up @@ -1695,8 +1695,10 @@ PyArray_FromAny_int(PyObject *op, PyArray_Descr *in_descr,
/* Decrease the number of dimensions to the detected ones */
int out_ndim = PyArray_NDIM(ret);
PyArray_Descr *out_descr = PyArray_DESCR(ret);
((PyArrayObject_fields *)ret)->nd = ndim;
((PyArrayObject_fields *)ret)->descr = dtype;
if (out_ndim != ndim) {
((PyArrayObject_fields *)ret)->nd = ndim;
((PyArrayObject_fields *)ret)->descr = dtype;
}

int success = PyArray_AssignFromCache(ret, cache);

Expand Down Expand Up @@ -1929,8 +1931,10 @@ PyArray_FromArray(PyArrayObject *arr, PyArray_Descr *newtype, int flags)

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;
if (actual_ndim != PyArray_NDIM(arr)) {
((PyArrayObject_fields *)ret)->nd = PyArray_NDIM(arr);
((PyArrayObject_fields *)ret)->descr = newtype;
}

int success = PyArray_CopyInto(ret, arr);

Expand Down
7 changes: 4 additions & 3 deletions numpy/core/src/multiarray/methods.c
Original file line number Diff line number Diff line change
Expand Up @@ -936,9 +936,10 @@ array_astype(PyArrayObject *self,
/* 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;

if (out_ndim != PyArray_NDIM(self)) {
((PyArrayObject_fields *)ret)->nd = PyArray_NDIM(self);
((PyArrayObject_fields *)ret)->descr = dtype;
}
int success = PyArray_CopyInto(ret, self);

Py_DECREF(dtype);
Expand Down
26 changes: 26 additions & 0 deletions numpy/core/tests/test_array_coercion.py
Original file line number Diff line number Diff line change
Expand Up @@ -870,3 +870,29 @@ def test_subarray_from_array_construction():

res = np.array(arr, dtype="(2,2)f")
assert_array_equal(res, expected)


def test_empty_string():
# Empty strings are unfortunately often converted to S1 and we need to
# make sure we are filling the S1 and not the (possibly) detected S0
# result. This should likely just return S0 and if not maybe the decision
# to return S1 should be moved.
res = np.array([""] * 10, dtype="S")
assert_array_equal(res, np.array("\0", "S1"))
assert res.dtype == "S1"

arr = np.array([""] * 10, dtype=object)

res = arr.astype("S")
assert_array_equal(res, b"")
assert res.dtype == "S1"

res = np.array(arr, dtype="S")
assert_array_equal(res, b"")
# TODO: This is arguably weird/wrong, but seems old:
assert res.dtype == f"S{np.dtype('O').itemsize}"

res = np.array([[""] * 10, arr], dtype="S")
assert_array_equal(res, b"")
assert res.shape == (2, 10)
assert res.dtype == "S1"

0 comments on commit 0d36673

Please sign in to comment.