summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
authorSebastian Berg <sebastian@sipsolutions.net>2021-06-23 20:14:17 -0500
committerSebastian Berg <sebastian@sipsolutions.net>2021-06-23 20:14:17 -0500
commit6af544fa49145c7075d32e239e1970d509f49630 (patch)
tree8e0652c2ccaa3b6b3e25e39286196ace344675eb /numpy
parent3fd9d675ac45b8a29402162cc0de646f7c6bf8c3 (diff)
downloadnumpy-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.c21
-rw-r--r--numpy/core/src/multiarray/convert_datatype.c6
-rw-r--r--numpy/core/src/multiarray/convert_datatype.h4
-rw-r--r--numpy/core/tests/test_casting_unittests.py3
-rw-r--r--numpy/core/tests/test_numeric.py16
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)