Skip to content

Commit 90ad3b2

Browse files
authored
fix: use accurate lower bound (#132)
1 parent 951282b commit 90ad3b2

File tree

3 files changed

+33
-6
lines changed

3 files changed

+33
-6
lines changed

pyproject.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ optional-dependencies.doc = [
3737
"sphinx-autofixture>=0.4.1",
3838
]
3939
optional-dependencies.full = [ "fast-array-utils[accel,dask,sparse]", "h5py", "zarr" ]
40-
optional-dependencies.sparse = [ "scipy>=1.11" ]
40+
optional-dependencies.sparse = [ "scipy>=1.13" ]
4141
optional-dependencies.test = [
4242
"anndata",
4343
"fast-array-utils[accel,test-min]",
@@ -102,6 +102,7 @@ overrides.matrix.resolution.features = [
102102
overrides.matrix.resolution.dependencies = [
103103
# TODO: move to min dep once this is fixed: https://github.com/tlambert03/hatch-min-requirements/issues/11
104104
{ if = [ "lowest" ], value = "dask==2023.6.1" },
105+
{ if = [ "lowest" ], value = "scipy==1.13.0" },
105106
]
106107

107108
[[tool.hatch.envs.hatch-test.matrix]]
@@ -174,6 +175,7 @@ filterwarnings = [
174175
"error",
175176
# codspeed seems to break this dtype added by h5py
176177
"ignore:.*numpy[.]longdouble:UserWarning",
178+
"ignore:FNV hashing is not implemented in Numba:UserWarning",
177179
]
178180
markers = [
179181
"benchmark: marks tests as benchmark (to run with `--codspeed`)",

src/testing/fast_array_utils/_array_type.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from dataclasses import KW_ONLY, dataclass, field
88
from functools import cached_property, partial
99
from importlib.metadata import version
10-
from typing import TYPE_CHECKING, Generic, TypeVar, cast
10+
from typing import TYPE_CHECKING, Generic, TypedDict, TypeVar, cast
1111

1212
import numpy as np
1313
from packaging.version import Version
@@ -378,12 +378,20 @@ def random_mat(
378378
m, n = shape
379379
return cast(
380380
"types.CSBase",
381-
random_spmat(m, n, density=density, format=format, dtype=dtype, rng=rng)
381+
random_spmat(m, n, density=density, format=format, dtype=dtype, **_rng_kw(rng))
382382
if container == "matrix"
383-
else random_sparr(shape, density=density, format=format, dtype=dtype, rng=rng),
383+
else random_sparr(shape, density=density, format=format, dtype=dtype, **_rng_kw(rng)),
384384
)
385385

386386

387+
class RngKw(TypedDict):
388+
rng: np.random.Generator | None
389+
390+
391+
def _rng_kw(rng: np.random.Generator | None) -> RngKw:
392+
return RngKw(rng=rng) if Version(version("scipy")) >= Version("1.15") else cast("RngKw", dict(random_state=rng))
393+
394+
387395
def _half_chunk_size(a: tuple[int, ...]) -> tuple[int, ...]:
388396
def half_rounded_up(x: int) -> int:
389397
div, mod = divmod(x, 2)

tests/test_stats.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# SPDX-License-Identifier: MPL-2.0
22
from __future__ import annotations
33

4+
from importlib.metadata import version
45
from importlib.util import find_spec
56
from pathlib import Path
67
from typing import TYPE_CHECKING, cast
@@ -9,6 +10,7 @@
910
import pytest
1011
import scipy.sparse as sps
1112
from numpy.exceptions import AxisError
13+
from packaging.version import Version
1214

1315
from fast_array_utils import stats, types
1416
from testing.fast_array_utils import SUPPORTED_TYPES, Flags
@@ -39,6 +41,11 @@
3941
ATS_CUPY_SPARSE = {at for at in SUPPORTED_TYPES if "cupyx.scipy" in str(at)}
4042

4143

44+
def _xfail_if_old_scipy(array_type: ArrayType[Any], ndim: Literal[1, 2]) -> pytest.MarkDecorator:
45+
cond = ndim == 1 and bool(array_type.flags & Flags.Sparse) and Version(version("scipy")) < Version("1.14")
46+
return pytest.mark.xfail(cond, reason="Sparse matrices don’t support 1d arrays")
47+
48+
4249
@pytest.fixture(
4350
scope="session",
4451
params=[
@@ -134,7 +141,10 @@ def pbmc64k_reduced_raw() -> sps.csr_array[np.float32]:
134141
@pytest.mark.array_type(skip={*ATS_SPARSE_DS, Flags.Matrix})
135142
@pytest.mark.parametrize("func", STAT_FUNCS)
136143
@pytest.mark.parametrize(("ndim", "axis"), [(1, 0), (2, 3), (2, -1)], ids=["1d-ax0", "2d-ax3", "2d-axneg"])
137-
def test_ndim_error(array_type: ArrayType[Array], func: StatFunNoDtype, ndim: Literal[1, 2], axis: Literal[0, 1] | None) -> None:
144+
def test_ndim_error(
145+
request: pytest.FixtureRequest, array_type: ArrayType[Array], func: StatFunNoDtype, ndim: Literal[1, 2], axis: Literal[0, 1] | None
146+
) -> None:
147+
request.applymarker(_xfail_if_old_scipy(array_type, ndim))
138148
check_ndim(array_type, ndim)
139149
# not using the fixture because we don’t need to test multiple dtypes
140150
np_arr = np.array([[1, 2, 3], [4, 5, 6]], dtype=np.float32)
@@ -148,12 +158,15 @@ def test_ndim_error(array_type: ArrayType[Array], func: StatFunNoDtype, ndim: Li
148158

149159
@pytest.mark.array_type(skip=ATS_SPARSE_DS)
150160
def test_sum(
161+
request: pytest.FixtureRequest,
151162
array_type: ArrayType[CpuArray | GpuArray | DiskArray | types.DaskArray],
152163
dtype_in: type[DTypeIn],
153164
dtype_arg: type[DTypeOut] | None,
154165
axis: Literal[0, 1] | None,
155166
np_arr: NDArray[DTypeIn],
167+
ndim: Literal[1, 2],
156168
) -> None:
169+
request.applymarker(_xfail_if_old_scipy(array_type, ndim))
157170
if np.dtype(dtype_arg).kind in "iu" and (array_type.flags & Flags.Gpu) and (array_type.flags & Flags.Sparse):
158171
pytest.skip("GPU sparse matrices don’t support int dtypes")
159172
arr = array_type(np_arr.copy())
@@ -209,7 +222,8 @@ def test_sum_dask_shapes(array_type: ArrayType[types.DaskArray], axis: Literal[0
209222

210223

211224
@pytest.mark.array_type(skip=ATS_SPARSE_DS)
212-
def test_mean(array_type: ArrayType[Array], axis: Literal[0, 1] | None, np_arr: NDArray[DTypeIn]) -> None:
225+
def test_mean(request: pytest.FixtureRequest, array_type: ArrayType[Array], axis: Literal[0, 1] | None, np_arr: NDArray[DTypeIn], ndim: Literal[1, 2]) -> None:
226+
request.applymarker(_xfail_if_old_scipy(array_type, ndim))
213227
arr = array_type(np_arr)
214228

215229
result = stats.mean(arr, axis=axis) # type: ignore[arg-type] # https://github.com/python/mypy/issues/16777
@@ -224,10 +238,13 @@ def test_mean(array_type: ArrayType[Array], axis: Literal[0, 1] | None, np_arr:
224238

225239
@pytest.mark.array_type(skip=Flags.Disk)
226240
def test_mean_var(
241+
request: pytest.FixtureRequest,
227242
array_type: ArrayType[CpuArray | GpuArray | types.DaskArray],
228243
axis: Literal[0, 1] | None,
229244
np_arr: NDArray[DTypeIn],
245+
ndim: Literal[1, 2],
230246
) -> None:
247+
request.applymarker(_xfail_if_old_scipy(array_type, ndim))
231248
arr = array_type(np_arr)
232249

233250
mean, var = stats.mean_var(arr, axis=axis, correction=1)

0 commit comments

Comments
 (0)