diff options
author | Charles Harris <charlesr.harris@gmail.com> | 2021-08-25 11:19:33 -0600 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-08-25 11:19:33 -0600 |
commit | 3712815c3209c4769ccad60de110f2bd8f3763ec (patch) | |
tree | a0c15c8d03af89e100548e3c6332d9a10ad9bf20 | |
parent | 90ddaa5f88cab3b9143877aa1bb78f80fc38a9ac (diff) | |
parent | a2a61e212fb1b8f27bc522b3769de93afdbb419d (diff) | |
download | numpy-3712815c3209c4769ccad60de110f2bd8f3763ec.tar.gz |
Merge pull request #19621 from seberg/fix-normal-ufunc-safety
BUG: The normal cast-safety for ufunc loops is "no" casting
-rw-r--r-- | numpy/core/src/umath/legacy_array_method.c | 4 | ||||
-rw-r--r-- | numpy/core/tests/test_ufunc.py | 31 |
2 files changed, 33 insertions, 2 deletions
diff --git a/numpy/core/src/umath/legacy_array_method.c b/numpy/core/src/umath/legacy_array_method.c index a5e123baa..4351f1d25 100644 --- a/numpy/core/src/umath/legacy_array_method.c +++ b/numpy/core/src/umath/legacy_array_method.c @@ -142,7 +142,7 @@ simple_legacy_resolve_descriptors( } } - return NPY_SAFE_CASTING; + return NPY_NO_CASTING; fail: for (int i = 0; i < nin + nout; i++) { @@ -244,7 +244,7 @@ PyArray_NewLegacyWrappingArrayMethod(PyUFuncObject *ufunc, .dtypes = signature, .flags = flags, .slots = slots, - .casting = NPY_EQUIV_CASTING, + .casting = NPY_NO_CASTING, }; PyBoundArrayMethodObject *bound_res = PyArrayMethod_FromSpec_int(&spec, 1); diff --git a/numpy/core/tests/test_ufunc.py b/numpy/core/tests/test_ufunc.py index 657b6a79b..c3ea10d93 100644 --- a/numpy/core/tests/test_ufunc.py +++ b/numpy/core/tests/test_ufunc.py @@ -536,6 +536,37 @@ class TestUfunc: np.add(arr, arr, dtype="m") np.maximum(arr, arr, dtype="m") + @pytest.mark.parametrize("ufunc", [np.add, np.sqrt]) + def test_cast_safety(self, ufunc): + """Basic test for the safest casts, because ufuncs inner loops can + indicate a cast-safety as well (which is normally always "no"). + """ + def call_ufunc(arr, **kwargs): + return ufunc(*(arr,) * ufunc.nin, **kwargs) + + arr = np.array([1., 2., 3.], dtype=np.float32) + arr_bs = arr.astype(arr.dtype.newbyteorder()) + expected = call_ufunc(arr) + # Normally, a "no" cast: + res = call_ufunc(arr, casting="no") + assert_array_equal(expected, res) + # Byte-swapping is not allowed with "no" though: + with pytest.raises(TypeError): + call_ufunc(arr_bs, casting="no") + + # But is allowed with "equiv": + res = call_ufunc(arr_bs, casting="equiv") + assert_array_equal(expected, res) + + # Casting to float64 is safe, but not equiv: + with pytest.raises(TypeError): + call_ufunc(arr_bs, dtype=np.float64, casting="equiv") + + # but it is safe cast: + res = call_ufunc(arr_bs, dtype=np.float64, casting="safe") + expected = call_ufunc(arr.astype(np.float64)) # upcast + assert_array_equal(expected, res) + def test_true_divide(self): a = np.array(10) b = np.array(20) |