diff options
| author | Sebastian Berg <sebastian@sipsolutions.net> | 2021-06-23 20:14:17 -0500 |
|---|---|---|
| committer | Sebastian Berg <sebastian@sipsolutions.net> | 2021-06-23 20:14:17 -0500 |
| commit | 6af544fa49145c7075d32e239e1970d509f49630 (patch) | |
| tree | 8e0652c2ccaa3b6b3e25e39286196ace344675eb /numpy | |
| parent | 3fd9d675ac45b8a29402162cc0de646f7c6bf8c3 (diff) | |
| download | numpy-6af544fa49145c7075d32e239e1970d509f49630.tar.gz | |
BUG: Fix cast safety and comparisons for zero sized voids
These are more complicated and weird things could happen...
right now, the only "weird" thing is that some sized to unsized
voids casts may be considered as safe when they should not be.
I think this is fine... In general, we need to fix all casts
to a strict interpretation of V0, S0, and U0 and then then
allow "V", "S", and "U" explicitly on the python entry-points
Right now, this is as minimal as I could make it work, it isn't
as minimal as I would _like_ after a release, but here we go...
Diffstat (limited to 'numpy')
| -rw-r--r-- | numpy/core/src/multiarray/arrayobject.c | 21 | ||||
| -rw-r--r-- | numpy/core/src/multiarray/convert_datatype.c | 6 | ||||
| -rw-r--r-- | numpy/core/src/multiarray/convert_datatype.h | 4 | ||||
| -rw-r--r-- | numpy/core/tests/test_casting_unittests.py | 3 | ||||
| -rw-r--r-- | numpy/core/tests/test_numeric.py | 16 |
5 files changed, 43 insertions, 7 deletions
diff --git a/numpy/core/src/multiarray/arrayobject.c b/numpy/core/src/multiarray/arrayobject.c index 78f547de2..55ba5601b 100644 --- a/numpy/core/src/multiarray/arrayobject.c +++ b/numpy/core/src/multiarray/arrayobject.c @@ -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" @@ -1358,9 +1359,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); @@ -1409,9 +1414,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); diff --git a/numpy/core/src/multiarray/convert_datatype.c b/numpy/core/src/multiarray/convert_datatype.c index d197a4bea..19127291a 100644 --- a/numpy/core/src/multiarray/convert_datatype.c +++ b/numpy/core/src/multiarray/convert_datatype.c @@ -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) { @@ -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; } diff --git a/numpy/core/src/multiarray/convert_datatype.h b/numpy/core/src/multiarray/convert_datatype.h index ba16d4d1b..22b3859d2 100644 --- a/numpy/core/src/multiarray/convert_datatype.h +++ b/numpy/core/src/multiarray/convert_datatype.h @@ -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, diff --git a/numpy/core/tests/test_casting_unittests.py b/numpy/core/tests/test_casting_unittests.py index 2cec1acd3..c15de3e88 100644 --- a/numpy/core/tests/test_casting_unittests.py +++ b/numpy/core/tests/test_casting_unittests.py @@ -147,6 +147,9 @@ class TestChanges: 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: diff --git a/numpy/core/tests/test_numeric.py b/numpy/core/tests/test_numeric.py index f5113150e..fe310058a 100644 --- a/numpy/core/tests/test_numeric.py +++ b/numpy/core/tests/test_numeric.py @@ -1724,6 +1724,22 @@ class TestArrayComparisons: 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) |
