Skip to content

Commit

Permalink
Merge pull request #19351 from charris/backport-19322
Browse files Browse the repository at this point in the history
BUG: Fix cast safety and comparisons for zero sized voids
  • Loading branch information
charris committed Jun 25, 2021
2 parents 79d1eb0 + 1765a18 commit 919318c
Show file tree
Hide file tree
Showing 5 changed files with 43 additions and 7 deletions.
21 changes: 15 additions & 6 deletions numpy/core/src/multiarray/arrayobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ maintainer email: oliphant.travis@ieee.org
#include "arraytypes.h"
#include "scalartypes.h"
#include "arrayobject.h"
#include "convert_datatype.h"
#include "conversion_utils.h"
#include "ctors.h"
#include "dtypemeta.h"
Expand Down Expand Up @@ -1390,9 +1391,13 @@ array_richcompare(PyArrayObject *self, PyObject *other, int cmp_op)
return Py_NotImplemented;
}

_res = PyArray_CanCastTypeTo(PyArray_DESCR(self),
PyArray_DESCR(array_other),
NPY_EQUIV_CASTING);
_res = PyArray_CheckCastSafety(
NPY_EQUIV_CASTING,
PyArray_DESCR(self), PyArray_DESCR(array_other), NULL);
if (_res < 0) {
PyErr_Clear();
_res = 0;
}
if (_res == 0) {
/* 2015-05-07, 1.10 */
Py_DECREF(array_other);
Expand Down Expand Up @@ -1441,9 +1446,13 @@ array_richcompare(PyArrayObject *self, PyObject *other, int cmp_op)
return Py_NotImplemented;
}

_res = PyArray_CanCastTypeTo(PyArray_DESCR(self),
PyArray_DESCR(array_other),
NPY_EQUIV_CASTING);
_res = PyArray_CheckCastSafety(
NPY_EQUIV_CASTING,
PyArray_DESCR(self), PyArray_DESCR(array_other), NULL);
if (_res < 0) {
PyErr_Clear();
_res = 0;
}
if (_res == 0) {
/* 2015-05-07, 1.10 */
Py_DECREF(array_other);
Expand Down
6 changes: 5 additions & 1 deletion numpy/core/src/multiarray/convert_datatype.c
Original file line number Diff line number Diff line change
Expand Up @@ -457,7 +457,7 @@ PyArray_GetCastSafety(
* is ignored).
* @return 0 for an invalid cast, 1 for a valid and -1 for an error.
*/
static int
NPY_NO_EXPORT int
PyArray_CheckCastSafety(NPY_CASTING casting,
PyArray_Descr *from, PyArray_Descr *to, PyArray_DTypeMeta *to_dtype)
{
Expand Down Expand Up @@ -2841,6 +2841,10 @@ cast_to_void_dtype_class(
loop_descrs[1]->elsize = given_descrs[0]->elsize;
Py_INCREF(given_descrs[0]);
loop_descrs[0] = given_descrs[0];
if (loop_descrs[0]->type_num == NPY_VOID &&
loop_descrs[0]->subarray == NULL && loop_descrs[1]->names == NULL) {
return NPY_NO_CASTING | _NPY_CAST_IS_VIEW;
}
return NPY_SAFE_CASTING | _NPY_CAST_IS_VIEW;
}

Expand Down
4 changes: 4 additions & 0 deletions numpy/core/src/multiarray/convert_datatype.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ NPY_NO_EXPORT NPY_CASTING
PyArray_GetCastSafety(
PyArray_Descr *from, PyArray_Descr *to, PyArray_DTypeMeta *to_dtype);

NPY_NO_EXPORT int
PyArray_CheckCastSafety(NPY_CASTING casting,
PyArray_Descr *from, PyArray_Descr *to, PyArray_DTypeMeta *to_dtype);

NPY_NO_EXPORT NPY_CASTING
legacy_same_dtype_resolve_descriptors(
PyArrayMethodObject *self,
Expand Down
3 changes: 3 additions & 0 deletions numpy/core/tests/test_casting_unittests.py
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,9 @@ def test_to_void(self):
assert not np.can_cast("U1", "V1")
# Structured to unstructured is just like any other:
assert np.can_cast("d,i", "V", casting="same_kind")
# Unstructured void to unstructured is actually no cast at all:
assert np.can_cast("V3", "V", casting="no")
assert np.can_cast("V0", "V", casting="no")


class TestCasting:
Expand Down
16 changes: 16 additions & 0 deletions numpy/core/tests/test_numeric.py
Original file line number Diff line number Diff line change
Expand Up @@ -1724,6 +1724,22 @@ def test_array_equiv(self):
assert_(not res)
assert_(type(res) is bool)

@pytest.mark.parametrize("dtype", ["V0", "V3", "V10"])
def test_compare_unstructured_voids(self, dtype):
zeros = np.zeros(3, dtype=dtype)

assert_array_equal(zeros, zeros)
assert not (zeros != zeros).any()

if dtype == "V0":
# Can't test != of actually different data
return

nonzeros = np.array([b"1", b"2", b"3"], dtype=dtype)

assert not (zeros == nonzeros).any()
assert (zeros != nonzeros).all()


def assert_array_strict_equal(x, y):
assert_array_equal(x, y)
Expand Down

0 comments on commit 919318c

Please sign in to comment.