diff --git a/CHANGELOG.md b/CHANGELOG.md index aa531908591f..688ca9e14f8f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ Also, that release drops support for Python 3.9, making Python 3.10 the minimum * Unified public API definitions in `dpnp.linalg` and `dpnp.scipy` submodules [#2663](https://github.com/IntelPython/dpnp/pull/2663) * Aligned the signature of `dpnp.reshape` function with Python array API by making `shape` a required argument [#2673](https://github.com/IntelPython/dpnp/pull/2673) * Unified `dpnp` public API exports by consolidating function exports in `__init__.py` and removing wildcard imports [#2665](https://github.com/IntelPython/dpnp/pull/2665) [#2666](https://github.com/IntelPython/dpnp/pull/2666) +* Updated tests to reflect the new scalar conversion rules for non-0D `usm_ndarray` [#2694](https://github.com/IntelPython/dpnp/pull/2694) ### Deprecated diff --git a/dpnp/tests/test_indexing.py b/dpnp/tests/test_indexing.py index 07b5488f09ea..9a55efe138b7 100644 --- a/dpnp/tests/test_indexing.py +++ b/dpnp/tests/test_indexing.py @@ -766,12 +766,18 @@ def test_axis_as_array(self): a = numpy.array([[[1]]]) ia = dpnp.array(a) - result = ia.take([0], axis=ia) - expected = a.take( - [0], axis=1 - ) # numpy raises an error for axis as array + # axis is a 0-D integer array + axis_0d = numpy.array(1) + iaxis_0d = dpnp.array(1) + + result = ia.take([0], axis=iaxis_0d) + expected = a.take([0], axis=axis_0d) assert_array_equal(result, expected) + # axis is not a 0-D integer array + assert_raises(TypeError, ia.take, [0], axis=ia) + assert_raises(TypeError, a.take, [0], axis=a) + def test_mode_raise(self): a = dpnp.array([[1, 2], [3, 4]]) assert_raises(ValueError, a.take, [-1, 4], mode="raise") diff --git a/dpnp/tests/test_ndarray.py b/dpnp/tests/test_ndarray.py index b829ad6f3527..c58c26fdf977 100644 --- a/dpnp/tests/test_ndarray.py +++ b/dpnp/tests/test_ndarray.py @@ -5,6 +5,7 @@ assert_allclose, assert_array_equal, assert_equal, + assert_raises, assert_raises_regex, ) @@ -530,43 +531,71 @@ def test_print_dpnp_zero_shape(): assert result == expected -# Numpy will raise an error when converting a.ndim > 0 to a scalar -# TODO: Discuss dpnp behavior according to these future changes -@pytest.mark.skip("until dpctl-2223") -@pytest.mark.filterwarnings("ignore::DeprecationWarning") -@pytest.mark.parametrize("func", [bool, float, int, complex]) +@testing.with_requires("numpy>=2.4") +@pytest.mark.parametrize("xp", [dpnp, numpy]) @pytest.mark.parametrize("shape", [tuple(), (1,), (1, 1), (1, 1, 1)]) -@pytest.mark.parametrize( - "dtype", get_all_dtypes(no_float16=False, no_complex=True) -) -def test_scalar_type_casting(func, shape, dtype): - a = numpy.full(shape, 5, dtype=dtype) - ia = dpnp.full(shape, 5, dtype=dtype) - assert func(a) == func(ia) - +class TestPythonScalarConversion: + @pytest.mark.parametrize( + "dtype", get_all_dtypes(no_none=True, no_float16=False, no_complex=True) + ) + def test_bool_conversion(self, xp, shape, dtype): + a = xp.full(shape, 5, dtype=dtype) + if xp == dpnp and len(shape) > 0: + # dpnp behavior differs from NumPy: + # non-0D singe-element arrays are not convertible to + # Python bool + assert_raises(TypeError, bool, a) + else: + # NumPy allows conversion to Python bool for + # non-0D singe-element arrays + assert bool(a) is True -# Numpy will raise an error when converting a.ndim > 0 to a scalar -# TODO: Discuss dpnp behavior according to these future changes -@pytest.mark.filterwarnings("ignore::DeprecationWarning") -@pytest.mark.skip("until dpctl-2223") -@pytest.mark.parametrize( - "method", ["__bool__", "__float__", "__int__", "__complex__"] -) -@pytest.mark.parametrize("shape", [tuple(), (1,), (1, 1), (1, 1, 1)]) -@pytest.mark.parametrize( - "dtype", get_all_dtypes(no_float16=False, no_complex=True) -) -def test_scalar_type_casting_by_method(method, shape, dtype): - a = numpy.full(shape, 4.7, dtype=dtype) - ia = dpnp.full(shape, 4.7, dtype=dtype) - assert_allclose(getattr(a, method)(), getattr(ia, method)(), rtol=1e-06) + @pytest.mark.parametrize( + "dtype", get_all_dtypes(no_none=True, no_float16=False, no_complex=True) + ) + def test_bool_method_conversion(self, xp, shape, dtype): + a = xp.full(shape, 5, dtype=dtype) + if xp == dpnp and len(shape) > 0: + assert_raises(TypeError, getattr(a, "__bool__")) + else: + assert a.__bool__() is True + + @pytest.mark.parametrize("func", [float, int, complex]) + @pytest.mark.parametrize( + "dtype", get_all_dtypes(no_none=True, no_float16=False, no_complex=True) + ) + def test_non_bool_conversion(self, xp, func, shape, dtype): + a = xp.full(shape, 5, dtype=dtype) + if len(shape) > 0: + # Non-0D arrays are not allowed to be converted to + # Python numeric scalars + assert_raises(TypeError, func, a) + else: + # 0D arrays are allowed to be converted to + # Python numeric scalars + expected = 1 if dtype == xp.bool else 5 + assert func(a) == func(expected) + + @pytest.mark.parametrize("method", ["__float__", "__int__", "__complex__"]) + @pytest.mark.parametrize( + "dtype", get_all_dtypes(no_none=True, no_float16=False, no_complex=True) + ) + def test_non_bool_method_conversion(self, xp, method, shape, dtype): + a = xp.full(shape, 5, dtype=dtype) + if len(shape) > 0: + assert_raises(TypeError, getattr(a, method)) + else: + expected = 1 if dtype == xp.bool else 5 + func = {"__float__": float, "__int__": int, "__complex__": complex}[ + method + ] + assert getattr(a, method)() == func(expected) -@pytest.mark.parametrize("shape", [(1,), (1, 1), (1, 1, 1)]) @pytest.mark.parametrize("index_dtype", [dpnp.int32, dpnp.int64]) -def test_array_as_index(shape, index_dtype): - ind_arr = dpnp.ones(shape, dtype=index_dtype) - a = numpy.arange(ind_arr.size + 1) +def test_array_as_index(index_dtype): + ind_arr = dpnp.ones((1,), dtype=index_dtype) + a = dpnp.arange(ind_arr.size + 1) assert a[tuple(ind_arr)] == a[1] diff --git a/dpnp/tests/third_party/cupy/core_tests/test_ndarray_unary_op.py b/dpnp/tests/third_party/cupy/core_tests/test_ndarray_unary_op.py index 3a1e30fc894e..651cad1454ae 100644 --- a/dpnp/tests/third_party/cupy/core_tests/test_ndarray_unary_op.py +++ b/dpnp/tests/third_party/cupy/core_tests/test_ndarray_unary_op.py @@ -25,13 +25,17 @@ def test_bool_scalar(self, dtype): assert not bool(cupy.array(0, dtype=dtype)) def test_bool_one_element_bool(self): - assert bool(cupy.array([True], dtype=numpy.bool_)) - assert not bool(cupy.array([False], dtype=numpy.bool_)) + # Different behavior from CuPy: + # CuPy as NumPy allows conversion to Python bool for + # non-0D singe-element arrays + with self.assertRaises(TypeError): + bool(cupy.array([True], dtype=numpy.bool_)) @testing.for_all_dtypes() def test_bool_one_element(self, dtype): - assert bool(cupy.array([1], dtype=dtype)) - assert not bool(cupy.array([0], dtype=dtype)) + # Different behavior from CuPy + with self.assertRaises(TypeError): + bool(cupy.array([1], dtype=dtype)) @testing.for_all_dtypes() def test_bool_two_elements(self, dtype): diff --git a/dpnp/tests/third_party/cupyx/scipy_tests/special_tests/test_erf.py b/dpnp/tests/third_party/cupyx/scipy_tests/special_tests/test_erf.py index 1bdee3dbe54c..224a0fd0eb6f 100644 --- a/dpnp/tests/third_party/cupyx/scipy_tests/special_tests/test_erf.py +++ b/dpnp/tests/third_party/cupyx/scipy_tests/special_tests/test_erf.py @@ -80,10 +80,10 @@ def test_erfinv_behavior(self, dtype): a[:] = 1.0 + 1e-6 a = cupy.scipy.special.erfinv(a) - assert cupy.isnan(a) + assert cupy.isnan(a).item() a[:] = -1.0 - 1e-6 a = cupy.scipy.special.erfinv(a) - assert cupy.isnan(a) + assert cupy.isnan(a).item() a[:] = 1.0 a = cupy.scipy.special.erfinv(a) assert numpy.isposinf(cupy.asnumpy(a)) @@ -98,10 +98,10 @@ def test_erfcinv_behavior(self, dtype): a[:] = 2.0 + 1e-6 a = cupy.scipy.special.erfcinv(a) - assert cupy.isnan(a) + assert cupy.isnan(a).item() a[:] = 0.0 - 1e-6 a = cupy.scipy.special.erfcinv(a) - assert cupy.isnan(a) + assert cupy.isnan(a).item() a[:] = 0.0 a = cupy.scipy.special.erfcinv(a) assert numpy.isposinf(cupy.asnumpy(a))