Skip to content

Commit 57e80d1

Browse files
crusaderkyNeilGirdhar
authored andcommitted
TST: NumPy 1.x support (data-apis#169)
* TST: NumPy 1.x support * Downgrade to oldest SPEC0
1 parent e79b886 commit 57e80d1

File tree

8 files changed

+1167
-19
lines changed

8 files changed

+1167
-19
lines changed

Diff for: .github/workflows/ci.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ jobs:
4848
strategy:
4949
fail-fast: false
5050
matrix:
51-
environment: [tests-py310, tests-py313, tests-backends]
51+
environment: [tests-py310, tests-py313, tests-numpy1, tests-backends]
5252
runs-on: [ubuntu-latest]
5353

5454
steps:

Diff for: pixi.lock

+1,140-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: pyproject.toml

+6
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ python = "~=3.10.0"
126126
[tool.pixi.feature.py313.dependencies]
127127
python = "~=3.13.0"
128128

129+
[tool.pixi.feature.numpy1.dependencies]
130+
# Oldest SPEC 0 NumPy at the moment of writing
131+
numpy = "=1.25.0"
132+
129133
# Backends that can run on CPU-only hosts
130134
[tool.pixi.feature.backends.dependencies]
131135
pytorch = "*"
@@ -167,6 +171,8 @@ tests = { features = ["tests"], solve-group = "default" }
167171
docs = { features = ["docs"], solve-group = "default" }
168172
dev = { features = ["lint", "tests", "docs", "dev", "backends"], solve-group = "default" }
169173
dev-cuda = { features = ["lint", "tests", "docs", "dev", "backends", "cuda-backends"] }
174+
dev-numpy1 = { features = ["lint", "tests", "dev", "numpy1"] }
175+
tests-numpy1 = ["py310", "tests", "numpy1"]
170176
tests-py310 = ["py310", "tests"]
171177
tests-py313 = ["py313", "tests"]
172178
# CUDA not available on free github actions and on some developers' PCs

Diff for: src/array_api_extra/_lib/_funcs.py

+4-5
Original file line numberDiff line numberDiff line change
@@ -565,12 +565,11 @@ def isclose(
565565
if rtol == 0:
566566
return xp.abs(a - b) <= atol
567567

568-
try:
569-
nrtol = xp.asarray(int(1.0 / rtol), dtype=b.dtype)
570-
except OverflowError:
571-
# rtol * max_int(dtype) < 1, so it's inconsequential
568+
# Don't rely on OverflowError, as it is not guaranteed by the Array API.
569+
nrtol = int(1.0 / rtol)
570+
if nrtol > xp.iinfo(b.dtype).max:
571+
# rtol * max_int < 1, so it's inconsequential
572572
return xp.abs(a - b) <= atol
573-
574573
return xp.abs(a - b) <= (atol + xp.abs(b) // nrtol)
575574

576575

Diff for: src/array_api_extra/_lib/_utils/_helpers.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -245,8 +245,7 @@ def eager_shape(x: Array, /) -> tuple[int, ...]:
245245

246246

247247
def meta_namespace(
248-
*arrays: Array | int | float | complex | bool | None,
249-
xp: ModuleType | None = None,
248+
*arrays: Array | complex | None, xp: ModuleType | None = None
250249
) -> ModuleType:
251250
"""
252251
Get the namespace of Dask chunks.

Diff for: tests/test_funcs.py

+10
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,9 @@
4848
lazy_xp_function(sinc, static_argnames="xp")
4949

5050

51+
NUMPY_GE2 = int(np.__version__.split(".")[0]) >= 2
52+
53+
5154
@pytest.mark.skip_xp_backend(
5255
Backend.SPARSE, reason="read-only backend without .at support"
5356
)
@@ -213,6 +216,13 @@ def test_hypothesis( # type: ignore[explicit-any,decorated-any]
213216
xp: ModuleType,
214217
library: Backend,
215218
):
219+
if (
220+
library in (Backend.NUMPY, Backend.NUMPY_READONLY)
221+
and not NUMPY_GE2
222+
and dtype is np.float32
223+
):
224+
pytest.xfail(reason="NumPy 1.x dtype promotion for scalars")
225+
216226
mbs = npst.mutually_broadcastable_shapes(num_shapes=n_arrays + 1, min_side=0)
217227
input_shapes, _ = data.draw(mbs)
218228
cond_shape, *shapes = input_shapes

Diff for: tests/test_helpers.py

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@
1818
from array_api_extra._lib._utils._typing import Array, Device, DType
1919
from array_api_extra.testing import lazy_xp_function
2020

21-
# mypy: disable-error-code=no-untyped-usage
21+
from .conftest import np_compat
2222

23-
np_compat = array_namespace(np.empty(0)) # type: ignore[arg-type] # pyright: ignore[reportArgumentType]
23+
# mypy: disable-error-code=no-untyped-usage
2424

2525
# FIXME calls xp.unique_values without size
2626
lazy_xp_function(in1d, jax_jit=False, static_argnames=("assume_unique", "invert", "xp"))
@@ -149,7 +149,7 @@ def test_numpy_generics(self, dtype: DType):
149149
which are subclasses of float and complex.
150150
"""
151151
a = cast(Array, dtype(0)) # type: ignore[operator] # pyright: ignore[reportCallIssue]
152-
xa, xb = asarrays(a, 0, xp=np)
152+
xa, xb = asarrays(a, 0, xp=np_compat)
153153
assert xa.dtype == dtype
154154
assert xb.dtype == dtype
155155

Diff for: tests/test_lazy.py

+2-7
Original file line numberDiff line numberDiff line change
@@ -94,12 +94,7 @@ def f(x: Array) -> tuple[Array, Array]:
9494
@pytest.mark.parametrize(
9595
"as_numpy",
9696
[
97-
pytest.param(
98-
False,
99-
marks=pytest.mark.xfail_xp_backend(
100-
Backend.TORCH, reason="illegal dtype promotion"
101-
),
102-
),
97+
False,
10398
pytest.param(
10499
True,
105100
marks=[
@@ -119,7 +114,7 @@ def f(x: Array, y: Array) -> tuple[Array, Array]:
119114
return x + y, x - y
120115

121116
x = xp.asarray([1, 2], dtype=xp.float32)
122-
y = xp.asarray(3, dtype=xp.float64)
117+
y = xp.asarray([3], dtype=xp.float64)
123118
expect = (
124119
xp.asarray([4, 5], dtype=xp.float64),
125120
xp.asarray([-2, -1], dtype=xp.float64),

0 commit comments

Comments
 (0)