Skip to content

Commit 97c1668

Browse files
Merge master into move_tensor_impl_ext
2 parents 6680790 + f4591e1 commit 97c1668

20 files changed

+297
-131
lines changed

.github/workflows/conda-package.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ env:
2020
test-env-name: 'test'
2121
rerun-tests-on-failure: 'true'
2222
rerun-tests-max-attempts: 2
23-
rerun-tests-timeout: 40
23+
rerun-tests-timeout: 45
2424

2525
jobs:
2626
build:

.github/workflows/openssf-scorecard.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,6 @@ jobs:
7272

7373
# Upload the results to GitHub's code scanning dashboard.
7474
- name: "Upload to code-scanning"
75-
uses: github/codeql-action/upload-sarif@19b2f06db2b6f5108140aeb04014ef02b648f789 # v4.31.11
75+
uses: github/codeql-action/upload-sarif@45cbd0c69e560cd9e7cd7f8c32362050c9b7ded2 # v4.32.2
7676
with:
7777
sarif_file: results.sarif

.pre-commit-config.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ repos:
127127
hooks:
128128
- id: actionlint
129129
- repo: https://github.com/BlankSpruce/gersemi
130-
rev: 0.25.1
130+
rev: 0.25.4
131131
hooks:
132132
- id: gersemi
133133
exclude: "dpnp/backend/cmake/Modules/"

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ Also, that release drops support for Python 3.9, making Python 3.10 the minimum
4545
* Updated `dpnp.fix` to reuse `dpnp.trunc` internally [#2722](https://github.com/IntelPython/dpnp/pull/2722)
4646
* Changed the build scripts and documentation due to `python setup.py develop` deprecation notice [#2716](https://github.com/IntelPython/dpnp/pull/2716)
4747
* Clarified behavior on repeated `axes` in `dpnp.tensordot` and `dpnp.linalg.tensordot` functions [#2733](https://github.com/IntelPython/dpnp/pull/2733)
48+
* Improved documentation of `file` argument in `dpnp.fromfile` [#2745](https://github.com/IntelPython/dpnp/pull/2745)
49+
* Aligned `dpnp.trim_zeros` with NumPy 2.4 to support a tuple of integers passed with `axis` keyword [#2746](https://github.com/IntelPython/dpnp/pull/2746)
4850

4951
### Deprecated
5052

doc/reference/set.rst

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ Boolean operations
2323
:toctree: generated/
2424
:nosignatures:
2525

26-
in1d
2726
intersect1d
2827
isin
2928
setdiff1d

dpnp/dpnp_iface_arraycreation.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1721,7 +1721,9 @@ def fromfile(
17211721
Parameters
17221722
----------
17231723
file : file or str or Path
1724-
Open file object or filename.
1724+
An open file object, a string containing the filename, or a Path object.
1725+
When reading from a file object it must support random access (i.e. it
1726+
must have tell and seek methods).
17251727
dtype : {None, str, dtype object}, optional
17261728
Data type of the returned array.
17271729
For binary files, it is used to determine the size and byte-order

dpnp/dpnp_iface_manipulation.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3983,7 +3983,7 @@ def trim_zeros(filt, trim="fb", axis=None):
39833983
(or index -1).
39843984
39853985
Default: ``"fb"``.
3986-
axis : {None, int}, optional
3986+
axis : {None, int, tuple of ints}, optional
39873987
If ``None``, `filt` is cropped such that the smallest bounding box is
39883988
returned that still contains all values which are not zero.
39893989
If an `axis` is specified, `filt` will be sliced in that dimension only
@@ -4038,11 +4038,14 @@ def trim_zeros(filt, trim="fb", axis=None):
40384038
raise ValueError(f"unexpected character(s) in `trim`: {trim!r}")
40394039

40404040
nd = filt.ndim
4041-
if axis is not None:
4042-
axis = normalize_axis_index(axis, nd)
4041+
if axis is None:
4042+
axis = tuple(range(nd))
4043+
else:
4044+
axis = normalize_axis_tuple(axis, nd, argname="axis")
40434045

4044-
if filt.size == 0:
4045-
return filt # no trailing zeros in empty array
4046+
# check if an empty array or no trimming requested
4047+
if filt.size == 0 or not axis:
4048+
return filt
40464049

40474050
non_zero = dpnp.argwhere(filt)
40484051
if non_zero.size == 0:
@@ -4061,13 +4064,10 @@ def trim_zeros(filt, trim="fb", axis=None):
40614064
else:
40624065
stop = (None,) * nd
40634066

4064-
if axis is None:
4065-
# trim all axes
4066-
sl = tuple(slice(*x) for x in zip(start, stop))
4067-
else:
4068-
# only trim single axis
4069-
sl = (slice(None),) * axis + (slice(start[axis], stop[axis]),) + (...,)
4070-
4067+
sl = tuple(
4068+
slice(start[ax], stop[ax]) if ax in axis else slice(None)
4069+
for ax in range(nd)
4070+
)
40714071
return filt[sl]
40724072

40734073

dpnp/tests/test_manipulation.py

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1432,6 +1432,8 @@ def test_usm_array(self):
14321432

14331433

14341434
class TestTrimZeros:
1435+
ALL_TRIMS = ["F", "B", "fb"]
1436+
14351437
@pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True))
14361438
def test_basic(self, dtype):
14371439
a = numpy.array([0, 0, 1, 0, 2, 3, 4, 0], dtype=dtype)
@@ -1443,7 +1445,7 @@ def test_basic(self, dtype):
14431445

14441446
@testing.with_requires("numpy>=2.2")
14451447
@pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True))
1446-
@pytest.mark.parametrize("trim", ["F", "B", "fb"])
1448+
@pytest.mark.parametrize("trim", ALL_TRIMS)
14471449
@pytest.mark.parametrize("ndim", [0, 1, 2, 3])
14481450
def test_basic_nd(self, dtype, trim, ndim):
14491451
a = numpy.ones((2,) * ndim, dtype=dtype)
@@ -1477,7 +1479,7 @@ def test_all_zero(self, dtype, trim):
14771479

14781480
@testing.with_requires("numpy>=2.2")
14791481
@pytest.mark.parametrize("dtype", get_all_dtypes(no_none=True))
1480-
@pytest.mark.parametrize("trim", ["F", "B", "fb"])
1482+
@pytest.mark.parametrize("trim", ALL_TRIMS)
14811483
@pytest.mark.parametrize("ndim", [0, 1, 2, 3])
14821484
def test_all_zero_nd(self, dtype, trim, ndim):
14831485
a = numpy.zeros((3,) * ndim, dtype=dtype)
@@ -1496,6 +1498,60 @@ def test_size_zero(self):
14961498
expected = numpy.trim_zeros(a)
14971499
assert_array_equal(result, expected)
14981500

1501+
@testing.with_requires("numpy>=2.4")
1502+
@pytest.mark.parametrize(
1503+
"shape, axis",
1504+
[
1505+
[(5,), None],
1506+
[(5,), ()],
1507+
[(5,), 0],
1508+
[(5, 6), None],
1509+
[(5, 6), ()],
1510+
[(5, 6), 0],
1511+
[(5, 6), (-1,)],
1512+
[(5, 6, 7), None],
1513+
[(5, 6, 7), ()],
1514+
[(5, 6, 7), 1],
1515+
[(5, 6, 7), (0, 2)],
1516+
[(5, 6, 7, 8), None],
1517+
[(5, 6, 7, 8), ()],
1518+
[(5, 6, 7, 8), -2],
1519+
[(5, 6, 7, 8), (0, 1, 3)],
1520+
],
1521+
)
1522+
@pytest.mark.parametrize("trim", ALL_TRIMS)
1523+
def test_multiple_axes(self, shape, axis, trim):
1524+
# standardize axis to a tuple
1525+
if axis is None:
1526+
axis = tuple(range(len(shape)))
1527+
elif isinstance(axis, int):
1528+
axis = (len(shape) + axis if axis < 0 else axis,)
1529+
else:
1530+
axis = tuple(len(shape) + ax if ax < 0 else ax for ax in axis)
1531+
1532+
# populate a random interior slice with nonzero entries
1533+
rng = numpy.random.default_rng(4321)
1534+
a = numpy.zeros(shape)
1535+
start = rng.integers(low=0, high=numpy.array(shape) - 1)
1536+
end = rng.integers(low=start + 1, high=shape)
1537+
shape = tuple(end - start)
1538+
data = 1 + rng.random(shape)
1539+
a[tuple(slice(i, j) for i, j in zip(start, end))] = data
1540+
ia = dpnp.array(a)
1541+
1542+
result = dpnp.trim_zeros(ia, axis=axis, trim=trim)
1543+
expected = numpy.trim_zeros(a, axis=axis, trim=trim)
1544+
assert_array_equal(result, expected)
1545+
1546+
# NOTE: numpy behaves differently on 0-sized input array
1547+
# and returns the input array with reduced shapes
1548+
@pytest.mark.parametrize("axis", [None, -1, 0])
1549+
@pytest.mark.parametrize("trim", ALL_TRIMS)
1550+
def test_empty_array(self, axis, trim):
1551+
a = dpnp.ones((0, 3))
1552+
result = dpnp.trim_zeros(a, axis=axis, trim=trim)
1553+
assert result is a
1554+
14991555
@pytest.mark.parametrize(
15001556
"a", [numpy.array([0, 2**62, 0]), numpy.array([0, 2**63, 0])]
15011557
)

dpnp/tests/third_party/cupy/core_tests/test_elementwise.py

Lines changed: 12 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import unittest
1+
from __future__ import annotations
22

33
import numpy
44
import pytest
@@ -12,7 +12,7 @@
1212
from dpnp.tests.third_party.cupy import testing
1313

1414

15-
class TestElementwise(unittest.TestCase):
15+
class TestElementwise:
1616

1717
def check_copy(self, dtype, src_id, dst_id):
1818
with cuda.Device(src_id):
@@ -33,7 +33,7 @@ def test_copy(self, dtype):
3333
def test_copy_multigpu_nopeer(self, dtype):
3434
if cuda.runtime.deviceCanAccessPeer(0, 1) == 1:
3535
pytest.skip("peer access is available")
36-
with self.assertRaises(ValueError):
36+
with pytest.raises(ValueError):
3737
self.check_copy(dtype, 0, 1)
3838

3939
@pytest.mark.skip("elementwise_copy() argument isn't supported")
@@ -74,27 +74,26 @@ def test_copy_orders(self, order):
7474

7575

7676
@pytest.mark.skip("`ElementwiseKernel` isn't supported")
77-
class TestElementwiseInvalidShape(unittest.TestCase):
77+
class TestElementwiseInvalidShape:
7878

7979
def test_invalid_shape(self):
80-
with self.assertRaisesRegex(ValueError, "Out shape is mismatched"):
80+
with pytest.raises(ValueError, match="Out shape is mismatched"):
8181
f = cupy.ElementwiseKernel("T x", "T y", "y += x")
8282
x = cupy.arange(12).reshape(3, 4)
8383
y = cupy.arange(4)
8484
f(x, y)
8585

8686

8787
@pytest.mark.skip("`ElementwiseKernel` isn't supported")
88-
class TestElementwiseInvalidArgument(unittest.TestCase):
88+
class TestElementwiseInvalidArgument:
8989

9090
def test_invalid_kernel_name(self):
91-
with self.assertRaisesRegex(ValueError, "Invalid kernel name"):
91+
with pytest.raises(ValueError, match="Invalid kernel name"):
9292
cupy.ElementwiseKernel("T x", "", "", "1")
9393

9494

95-
class TestElementwiseType(unittest.TestCase):
95+
class TestElementwiseType:
9696

97-
@testing.with_requires("numpy>=2.0")
9897
@testing.for_int_dtypes(no_bool=True)
9998
@testing.numpy_cupy_array_equal(accept_error=OverflowError)
10099
def test_large_int_upper_1(self, xp, dtype):
@@ -105,14 +104,6 @@ def test_large_int_upper_1(self, xp, dtype):
105104
@testing.for_int_dtypes(no_bool=True)
106105
@testing.numpy_cupy_array_equal(accept_error=OverflowError)
107106
def test_large_int_upper_2(self, xp, dtype):
108-
if numpy_version() < "2.0.0":
109-
flag = dtype in [xp.int16, xp.int32, xp.int64, xp.longlong]
110-
if xp.issubdtype(dtype, xp.unsignedinteger) or flag:
111-
pytest.skip("numpy doesn't raise OverflowError")
112-
113-
if dtype in [xp.int8, xp.intc] and is_win_platform():
114-
pytest.skip("numpy promotes dtype differently")
115-
116107
a = xp.array([1], dtype=xp.int8)
117108
b = xp.iinfo(dtype).max - 1
118109
return a + b
@@ -121,62 +112,38 @@ def test_large_int_upper_2(self, xp, dtype):
121112
@testing.numpy_cupy_array_equal()
122113
def test_large_int_upper_3(self, xp, dtype):
123114
if (
124-
numpy.issubdtype(dtype, numpy.unsignedinteger)
125-
and numpy_version() < "2.0.0"
126-
):
127-
pytest.skip("numpy promotes dtype differently")
128-
elif (
129115
dtype in (numpy.uint64, numpy.ulonglong)
130116
and not has_support_aspect64()
131117
):
132118
pytest.skip("no fp64 support")
133119

134120
a = xp.array([xp.iinfo(dtype).max], dtype=dtype)
135-
b = numpy.int8(0)
121+
b = xp.int8(0)
136122
return a + b
137123

138124
@testing.for_int_dtypes(no_bool=True)
139125
@testing.numpy_cupy_array_equal()
140126
def test_large_int_upper_4(self, xp, dtype):
141127
if (
142-
numpy.issubdtype(dtype, numpy.unsignedinteger)
143-
and numpy_version() < "2.0.0"
144-
):
145-
pytest.skip("numpy promotes dtype differently")
146-
elif (
147128
dtype in (numpy.uint64, numpy.ulonglong)
148129
and not has_support_aspect64()
149130
):
150131
pytest.skip("no fp64 support")
151132

152133
a = xp.array([xp.iinfo(dtype).max - 1], dtype=dtype)
153-
b = numpy.int8(1)
134+
b = xp.int8(1)
154135
return a + b
155136

156137
@testing.for_int_dtypes(no_bool=True)
157138
@testing.numpy_cupy_array_equal(accept_error=OverflowError)
158139
def test_large_int_lower_1(self, xp, dtype):
159-
if numpy_version() < "2.0.0":
160-
if dtype in [xp.int16, xp.int32, xp.int64, xp.longlong]:
161-
pytest.skip("numpy doesn't raise OverflowError")
162-
163-
if dtype in [xp.int8, xp.intc] and is_win_platform():
164-
pytest.skip("numpy promotes dtype differently")
165-
166140
a = xp.array([0], dtype=xp.int8)
167141
b = xp.iinfo(dtype).min
168142
return a + b
169143

170144
@testing.for_int_dtypes(no_bool=True)
171145
@testing.numpy_cupy_array_equal(accept_error=OverflowError)
172146
def test_large_int_lower_2(self, xp, dtype):
173-
if numpy_version() < "2.0.0":
174-
if dtype in [xp.int16, xp.int32, xp.int64, xp.longlong]:
175-
pytest.skip("numpy doesn't raise OverflowError")
176-
177-
if dtype in [xp.int8, xp.intc] and is_win_platform():
178-
pytest.skip("numpy promotes dtype differently")
179-
180147
a = xp.array([-1], dtype=xp.int8)
181148
b = xp.iinfo(dtype).min + 1
182149
return a + b
@@ -185,18 +152,13 @@ def test_large_int_lower_2(self, xp, dtype):
185152
@testing.numpy_cupy_array_equal()
186153
def test_large_int_lower_3(self, xp, dtype):
187154
if (
188-
numpy.issubdtype(dtype, numpy.unsignedinteger)
189-
and numpy_version() < "2.0.0"
190-
):
191-
pytest.skip("numpy promotes dtype differently")
192-
elif (
193155
dtype in (numpy.uint64, numpy.ulonglong)
194156
and not has_support_aspect64()
195157
):
196158
pytest.skip("no fp64 support")
197159

198160
a = xp.array([xp.iinfo(dtype).min], dtype=dtype)
199-
b = numpy.int8(0)
161+
b = xp.int8(0)
200162
return a + b
201163

202164
@testing.for_int_dtypes(no_bool=True)
@@ -209,5 +171,5 @@ def test_large_int_lower_4(self, xp, dtype):
209171
pytest.skip("no fp64 support")
210172

211173
a = xp.array([xp.iinfo(dtype).min + 1], dtype=dtype)
212-
b = numpy.int8(-1)
174+
b = xp.int8(-1)
213175
return a + b

dpnp/tests/third_party/cupy/core_tests/test_function.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
from __future__ import annotations
22

3-
import unittest
4-
3+
import numpy
54
import pytest
65

76
import dpnp as cupy
@@ -23,7 +22,7 @@ def _compile_func(kernel_name, code):
2322
return mod.get_function(kernel_name)
2423

2524

26-
class TestFunction(unittest.TestCase):
25+
class TestFunction:
2726

2827
def test_python_scalar(self):
2928
code = """

0 commit comments

Comments
 (0)