From 5889da6c0e8f833cac75b11dc99b7ebdda11ad0b Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Mon, 18 May 2026 07:18:04 +0200 Subject: [PATCH 01/13] Remove TODO from dpnp.linalg.matrix_rank() tests --- dpnp/tests/test_linalg.py | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/dpnp/tests/test_linalg.py b/dpnp/tests/test_linalg.py index e0225ec5060..de9f7891f56 100644 --- a/dpnp/tests/test_linalg.py +++ b/dpnp/tests/test_linalg.py @@ -3238,8 +3238,7 @@ def test_errors(self): ValueError, dpnp.linalg.matrix_rank, a_dp, tol=1e-06, rtol=1e-04 ) - # TODO: use below fixture when NumPy 2.5 is released - # @testing.with_requires("numpy>=2.5") + @testing.with_requires("numpy>=2.4.5") @pytest.mark.parametrize( "shape", [ @@ -3258,14 +3257,7 @@ def test_empty(self, shape): ia = dpnp.array(a) result = dpnp.linalg.matrix_rank(ia) - if numpy_version() < "2.5.0": # TODO: remove - # Expected behavior: rank of empty matrix is 0 - # For stacked matrices, return array of zeros - expected = numpy.zeros(shape[:-2], dtype=numpy.intp) - if expected.ndim == 0: - expected = numpy.array(0) - else: - expected = numpy.linalg.matrix_rank(a) + expected = numpy.linalg.matrix_rank(a) assert_array_equal(result, expected, strict=True) # Also test with hermitian=True From 9fcca7fea3d8f2f3ef5a78be42f457884291cb8f Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Mon, 18 May 2026 07:33:05 +0200 Subject: [PATCH 02/13] Update conj() tests due to regression in numpy 2.4.5 --- dpnp/tests/test_mathematical.py | 1 + .../cupy/core_tests/test_ndarray_complex_ops.py | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/dpnp/tests/test_mathematical.py b/dpnp/tests/test_mathematical.py index 8de7ec2ed80..c2e0fc32242 100644 --- a/dpnp/tests/test_mathematical.py +++ b/dpnp/tests/test_mathematical.py @@ -72,6 +72,7 @@ def test_angle_complex(self, dtype, deg): class TestConj: + @testing.with_requires("numpy!=2.4.5") @pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True)) def test_conj(self, dtype): a = generate_random_numpy_array(20, dtype) diff --git a/dpnp/tests/third_party/cupy/core_tests/test_ndarray_complex_ops.py b/dpnp/tests/third_party/cupy/core_tests/test_ndarray_complex_ops.py index a2fe0e2f256..b13e326c745 100644 --- a/dpnp/tests/third_party/cupy/core_tests/test_ndarray_complex_ops.py +++ b/dpnp/tests/third_party/cupy/core_tests/test_ndarray_complex_ops.py @@ -13,6 +13,8 @@ class TestConj: @testing.numpy_cupy_array_almost_equal() def test_conj(self, xp, dtype): x = testing.shaped_arange((2, 3), xp, dtype) + if xp is numpy and numpy.__version__ == "2.4.5" and x.dtype == bool: + return x # NumPy 2.4.5 had a regression for bool_arr.conj() return x.conj() @testing.for_all_dtypes(no_complex=True) @@ -20,6 +22,8 @@ def test_conj(self, xp, dtype): def test_conj_pass(self, xp, dtype): x = testing.shaped_arange((2, 3), xp, dtype) y = x.conj() + if xp is numpy and numpy.__version__ == "2.4.5": + return x # NumPy 2.4.5 had a regression for bool_arr.conj() assert x is y return y @@ -27,6 +31,8 @@ def test_conj_pass(self, xp, dtype): @testing.numpy_cupy_array_almost_equal() def test_conjugate(self, xp, dtype): x = testing.shaped_arange((2, 3), xp, dtype) + if xp is numpy and numpy.__version__ == "2.4.5" and x.dtype == bool: + return x # NumPy 2.4.5 had a regression for bool_arr.conj() return x.conjugate() @testing.for_all_dtypes(no_complex=True) @@ -34,6 +40,8 @@ def test_conjugate(self, xp, dtype): def test_conjugate_pass(self, xp, dtype): x = testing.shaped_arange((2, 3), xp, dtype) y = x.conjugate() + if xp is numpy and numpy.__version__ == "2.4.5": + return x # NumPy 2.4.5 had a regression for bool_arr.conj() assert x is y return y From 966bd41236d8240638b2b5bce36cc88d205446e2 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Mon, 18 May 2026 08:00:28 +0200 Subject: [PATCH 03/13] Extend gcd overflow testing --- dpnp/tests/test_binary_ufuncs.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/dpnp/tests/test_binary_ufuncs.py b/dpnp/tests/test_binary_ufuncs.py index 0de83c5b99c..f638fbf2ac1 100644 --- a/dpnp/tests/test_binary_ufuncs.py +++ b/dpnp/tests/test_binary_ufuncs.py @@ -1014,16 +1014,21 @@ def test_broadcasting(self, func, dt): result = getattr(dpnp, func)(ia, b) assert_array_equal(result, expected) - @pytest.mark.parametrize("dt", [numpy.int32, numpy.int64]) - def test_gcd_overflow(self, dt): - a = dt(numpy.iinfo(dt).min) # negative power of two - ia = dpnp.array(a) - q = -(a // 4) + @pytest.mark.parametrize("sign", [1, -1]) + @pytest.mark.parametrize("dt", get_integer_dtypes(no_unsigned=True)) + def test_gcd_overflow(self, sign, dt): + a = dt(numpy.iinfo(dt).min) # INT_MIN + q = (a // 4) * sign + ia, iq = dpnp.array(a), dpnp.array(q) # verify that we don't overflow when taking abs(x) # not relevant for lcm, where the result is unrepresentable anyway - expected = numpy.gcd(a, q) - result = dpnp.gcd(ia, q) + expected = numpy.gcd(a, q * 3) + result = dpnp.gcd(ia, iq * 3) + assert_array_equal(result, expected) + + expected = numpy.gcd(q * 3, a) + result = dpnp.gcd(iq * 3, ia) assert_array_equal(result, expected) def test_lcm_overflow(self): From 55109ec09dbc5431915ebdd5dbc3830a6992af69 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Mon, 18 May 2026 08:08:14 +0200 Subject: [PATCH 04/13] Remove TODO for dpnp.linalg.cond() test --- dpnp/tests/test_linalg.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/dpnp/tests/test_linalg.py b/dpnp/tests/test_linalg.py index de9f7891f56..be8987ab066 100644 --- a/dpnp/tests/test_linalg.py +++ b/dpnp/tests/test_linalg.py @@ -290,8 +290,7 @@ def test_empty(self, shape, p): expected = numpy.linalg.cond(a, p=p) assert_dtype_allclose(result, expected) - # TODO: uncomment once numpy 2.3.3 release is published - # @testing.with_requires("numpy>=2.3.3") + @testing.with_requires("numpy>=2.3.3") @pytest.mark.parametrize( "dtype", get_all_dtypes(no_none=True, no_bool=True) ) @@ -305,9 +304,6 @@ def test_basic(self, dtype, shape, p): result = dpnp.linalg.cond(ia, p=p) expected = numpy.linalg.cond(a, p=p) - # TODO: remove when numpy#29333 is released - if numpy_version() < "2.3.3": - expected = expected.real assert_dtype_allclose(result, expected, factor=16) @pytest.mark.parametrize("p", _norms) From f23768736ae7e7bd2d10603cb42bb1028d5c43ca Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Mon, 18 May 2026 08:12:50 +0200 Subject: [PATCH 05/13] Remove TODO for dpnp.size() test --- dpnp/tests/test_manipulation.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/dpnp/tests/test_manipulation.py b/dpnp/tests/test_manipulation.py index 4fc4b8cb161..c54756852b3 100644 --- a/dpnp/tests/test_manipulation.py +++ b/dpnp/tests/test_manipulation.py @@ -90,16 +90,15 @@ def test_size(self): assert dpnp.size(ia, 1) == numpy.size(a, 1) - # TODO: include commented code in the test when numpy-2.4 is released - # @testing.with_requires("numpy>=2.4") - def test_size_tuple(self): + @testing.with_requires("numpy>=2.4") + @pytest.mark.parametrize("axis", [(), (0,), (1,), (0, 1)]) + def test_size_tuple(self, axis): a = [[1, 2, 3], [4, 5, 6]] ia = dpnp.array(a) - assert dpnp.size(ia, ()) == 1 # numpy.size(a, ()) - assert dpnp.size(ia, (0,)) == 2 # numpy.size(a, (0,)) - assert dpnp.size(ia, (1,)) == 3 # numpy.size(a, (1,)) - assert dpnp.size(ia, (0, 1)) == 6 # numpy.size(a, (0, 1)) + result = dpnp.size(ia, axis=axis) + expected = numpy.size(a, axis=axis) + assert result == expected class TestAppend: From e8786a961e3becf6982cdabd8face090bd0c5716 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Mon, 18 May 2026 08:20:48 +0200 Subject: [PATCH 06/13] Remove TODO for dpnp.unique() tests --- dpnp/tests/test_manipulation.py | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/dpnp/tests/test_manipulation.py b/dpnp/tests/test_manipulation.py index c54756852b3..d09f19f1d77 100644 --- a/dpnp/tests/test_manipulation.py +++ b/dpnp/tests/test_manipulation.py @@ -23,7 +23,6 @@ get_integer_float_dtypes, get_unsigned_dtypes, has_support_aspect64, - numpy_version, ) from .third_party.cupy import testing @@ -90,7 +89,7 @@ def test_size(self): assert dpnp.size(ia, 1) == numpy.size(a, 1) - @testing.with_requires("numpy>=2.4") + @testing.with_requires("numpy>=2.4.0") @pytest.mark.parametrize("axis", [(), (0,), (1,), (0, 1)]) def test_size_tuple(self, axis): a = [[1, 2, 3], [4, 5, 6]] @@ -1890,8 +1889,7 @@ def test_equal_nan(self, eq_nan_kwd): expected = numpy.unique(a, **eq_nan_kwd) assert_array_equal(result, expected) - # TODO: uncomment once numpy 2.4.0 release is published - # @testing.with_requires("numpy>=2.4.0") + @testing.with_requires("numpy>=2.4.0") @pytest.mark.parametrize("axis", [0, -1]) def test_1d_equal_nan_axis(self, axis): a = numpy.array([numpy.nan, 0, 0, numpy.nan]) @@ -1899,16 +1897,11 @@ def test_1d_equal_nan_axis(self, axis): result = dpnp.unique(ia, axis=axis, equal_nan=True) expected = numpy.unique(a, axis=axis, equal_nan=True) - # TODO: remove when numpy#29372 is released - if numpy_version() < "2.4.0": - expected = numpy.array([0.0, numpy.nan]) assert_array_equal(result, expected) - # TODO: uncomment once numpy 2.4.0 release is published - # @testing.with_requires("numpy>=2.4.0") + @testing.with_requires("numpy>=2.4.0") @pytest.mark.parametrize("equal_nan", [True, False]) - # @pytest.mark.parametrize("xp", [numpy, dpnp]) - @pytest.mark.parametrize("xp", [dpnp]) + @pytest.mark.parametrize("xp", [numpy, dpnp]) def test_1d_axis_float_raises_typeerror(self, xp, equal_nan): a = xp.array([xp.nan, 0, 0, xp.nan]) with pytest.raises(TypeError, match="integer argument expected"): From 1bee69b862f1635df2c850847bed190967cff12b Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Mon, 18 May 2026 08:24:09 +0200 Subject: [PATCH 07/13] Remove TODO for dpnp.sinc() test --- dpnp/tests/test_mathematical.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/dpnp/tests/test_mathematical.py b/dpnp/tests/test_mathematical.py index c2e0fc32242..3dcae2ac269 100644 --- a/dpnp/tests/test_mathematical.py +++ b/dpnp/tests/test_mathematical.py @@ -1675,15 +1675,13 @@ def test_zero(self, dt): flag = dt in [numpy.int8, numpy.int16, numpy.uint8, numpy.uint16] assert_dtype_allclose(result, expected, check_only_type_kind=flag) - # TODO: add a proper NumPy version once resolved - @testing.with_requires("numpy>=2.0.0") + @testing.with_requires("numpy>=2.3.0") def test_zero_fp16(self): a = numpy.array([0.0], dtype=numpy.float16) ia = dpnp.array(a) result = dpnp.sinc(ia) - # expected = numpy.sinc(a) # numpy returns NaN, but expected 1.0 - expected = numpy.ones_like(a) + expected = numpy.sinc(a) assert_dtype_allclose(result, expected) @pytest.mark.usefixtures("suppress_invalid_numpy_warnings") From 803768ff4817b1a00611d5ac2e2730013ce382d6 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Mon, 18 May 2026 08:28:05 +0200 Subject: [PATCH 08/13] Remove w/a for supporting all dtypes in third party tests --- .../third_party/cupy/core_tests/test_nep50_examples.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/dpnp/tests/third_party/cupy/core_tests/test_nep50_examples.py b/dpnp/tests/third_party/cupy/core_tests/test_nep50_examples.py index 44f5433281e..4e7e7b99dc5 100644 --- a/dpnp/tests/third_party/cupy/core_tests/test_nep50_examples.py +++ b/dpnp/tests/third_party/cupy/core_tests/test_nep50_examples.py @@ -1,15 +1,8 @@ -import numpy import pytest -import dpnp as cp from dpnp.tests.helper import has_support_aspect64 from dpnp.tests.third_party.cupy import testing -# TODO: remove once all dtype aliases added -cp.int8 = numpy.int8 -cp.uint8 = numpy.uint8 -cp.int16 = numpy.int16 - # "example string" or # ("example string", "xfail message") examples = [ From 6b5ab2fd6eabbad04f401d0e3d7d81e38a15e2b6 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Mon, 18 May 2026 08:30:38 +0200 Subject: [PATCH 09/13] Remove TODO for dpnp.choose() test --- dpnp/tests/third_party/cupy/indexing_tests/test_indexing.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/dpnp/tests/third_party/cupy/indexing_tests/test_indexing.py b/dpnp/tests/third_party/cupy/indexing_tests/test_indexing.py index f28d7647f14..bec8f4204b3 100644 --- a/dpnp/tests/third_party/cupy/indexing_tests/test_indexing.py +++ b/dpnp/tests/third_party/cupy/indexing_tests/test_indexing.py @@ -204,10 +204,6 @@ class TestChoose(unittest.TestCase): @testing.for_all_dtypes() @testing.numpy_cupy_array_equal() def test_choose(self, xp, dtype): - # TODO: include additional dtype when dpnp#2201 is merged - dtype_list = [xp.int8, xp.int16] - if dtype in dtype_list or xp.issubdtype(dtype, xp.unsignedinteger): - pytest.skip("dpnp.choose() does not support new integer dtypes.") a = xp.array([0, 2, 1, 2]) c = testing.shaped_arange((3, 4), xp, dtype) return a.choose(c) From 61d3dcca21ba9c55b01e6714f3e07d92dcb8da8a Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Mon, 18 May 2026 08:42:00 +0200 Subject: [PATCH 10/13] Remove unused fixture in dpnp.correlate() tests --- .../third_party/cupy/statistics_tests/test_correlation.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dpnp/tests/third_party/cupy/statistics_tests/test_correlation.py b/dpnp/tests/third_party/cupy/statistics_tests/test_correlation.py index 604e545e078..4eaaf0ddf03 100644 --- a/dpnp/tests/third_party/cupy/statistics_tests/test_correlation.py +++ b/dpnp/tests/third_party/cupy/statistics_tests/test_correlation.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy @@ -226,7 +228,6 @@ def test_correlate_diff_types(self, xp, dtype1, dtype2, mode): @testing.parameterize(*testing.product({"mode": ["valid", "same", "full"]})) -@pytest.mark.usefixtures("allow_fall_back_on_numpy") class TestCorrelateInvalid(unittest.TestCase): @testing.with_requires("numpy>=1.18") From 78d216617fb9c6d275bccf873e4e524e26052baf Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Mon, 18 May 2026 08:49:32 +0200 Subject: [PATCH 11/13] Remove TODO for dpnp.ndarray.put() test --- dpnp/tests/test_indexing.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/dpnp/tests/test_indexing.py b/dpnp/tests/test_indexing.py index 2edc8214f3e..29939740a40 100644 --- a/dpnp/tests/test_indexing.py +++ b/dpnp/tests/test_indexing.py @@ -661,10 +661,11 @@ def test_empty(self, dtype, mode): dpnp.put(ia, [1, 2, 3], [], mode=mode) assert_array_equal(ia, a) - # TODO: enable test for numpy also since 2.0 + @testing.with_requires("numpy>=2.0") + @pytest.mark.parametrize("xp", [dpnp, numpy]) @pytest.mark.parametrize("mode", ["clip", "wrap"]) - def test_empty_input(self, mode): - empty = dpnp.asarray(list()) + def test_empty_input(self, xp, mode): + empty = xp.asarray(list()) with pytest.raises(IndexError): empty.put(1, 1, mode=mode) From b0b8a86ed0c3243ce4a6927946fa85bec01fae70 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Mon, 18 May 2026 08:53:16 +0200 Subject: [PATCH 12/13] Add compatibility note to the changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ab377b2b69c..eff314d5a85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [0.21.0] - MM/DD/2026 +This release is compatible with NumPy 2.4.5. + ### Added * Added C API functions for `dpnp.tensor.usm_ndarray` setters and getters to avoid ABI breakage if `dpnp.tensor.usm_ndarray` is modified [gh-2866](https://github.com/IntelPython/dpnp/pull/2866) From d2321ee26d392c237924cc9efaa5ef199bae5fb5 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Mon, 18 May 2026 09:04:56 +0200 Subject: [PATCH 13/13] Add PR to the changelog --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eff314d5a85..0c50fc5534f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [0.21.0] - MM/DD/2026 +## [0.21.0] - 2026-MM-DD This release is compatible with NumPy 2.4.5. @@ -13,9 +13,10 @@ This release is compatible with NumPy 2.4.5. * Added C API functions for `dpnp.tensor.usm_ndarray` setters and getters to avoid ABI breakage if `dpnp.tensor.usm_ndarray` is modified [gh-2866](https://github.com/IntelPython/dpnp/pull/2866) ### Changed -* Changed `dpnp.meshgrid` and `dpnp.tensor.meshgrid` to return a tuple instead of a list, aligning with NumPy 2.5+ behavior and 2025.12 version of the Python array API standard [#2854](https://github.com/IntelPython/dpnp/pull/2854) +* Changed `dpnp.meshgrid` and `dpnp.tensor.meshgrid` to return a tuple instead of a list, aligning with NumPy 2.5+ behavior and 2025.12 version of the Python array API standard [#2854](https://github.com/IntelPython/dpnp/pull/2854) * Updated `searchsorted` implementations to align with the 2025.12 array API spec [gh-2902](https://github.com/IntelPython/dpnp/pull/2902) +* Updated tests to align with NumPy 2.4.5 compatibility [gh-2920](https://github.com/IntelPython/dpnp/pull/2920) ### Deprecated