From 7dfb36546d0ee2af408b3c85840d1ef87678cc46 Mon Sep 17 00:00:00 2001 From: Jim Crist-Harif Date: Fri, 15 May 2026 12:21:14 -0500 Subject: [PATCH 1/6] Bump min numpy to 1.26, test old numpy versions --- conda/environments/all_cuda-129_arch-aarch64.yaml | 2 +- conda/environments/all_cuda-129_arch-x86_64.yaml | 2 +- conda/environments/all_cuda-132_arch-aarch64.yaml | 2 +- conda/environments/all_cuda-132_arch-x86_64.yaml | 2 +- conda/recipes/cuml/recipe.yaml | 2 +- dependencies.yaml | 5 ++++- python/cuml/pyproject.toml | 2 +- 7 files changed, 10 insertions(+), 7 deletions(-) diff --git a/conda/environments/all_cuda-129_arch-aarch64.yaml b/conda/environments/all_cuda-129_arch-aarch64.yaml index 699e9872f3..f70b17a786 100644 --- a/conda/environments/all_cuda-129_arch-aarch64.yaml +++ b/conda/environments/all_cuda-129_arch-aarch64.yaml @@ -47,7 +47,7 @@ dependencies: - nltk - numba-cuda>=0.22.2,<0.29.0 - numba>=0.60.0,<0.65.0 -- numpy>=1.23,<3.0 +- numpy>=1.26,<3.0 - numpydoc - numpydoc<1.9 - nvidia-ml-py>=12 diff --git a/conda/environments/all_cuda-129_arch-x86_64.yaml b/conda/environments/all_cuda-129_arch-x86_64.yaml index 644e0132e7..130a281624 100644 --- a/conda/environments/all_cuda-129_arch-x86_64.yaml +++ b/conda/environments/all_cuda-129_arch-x86_64.yaml @@ -46,7 +46,7 @@ dependencies: - nltk - numba-cuda>=0.22.2,<0.29.0 - numba>=0.60.0,<0.65.0 -- numpy>=1.23,<3.0 +- numpy>=1.26,<3.0 - numpydoc - numpydoc<1.9 - nvidia-ml-py>=12 diff --git a/conda/environments/all_cuda-132_arch-aarch64.yaml b/conda/environments/all_cuda-132_arch-aarch64.yaml index 692f50dbd6..40981932cf 100644 --- a/conda/environments/all_cuda-132_arch-aarch64.yaml +++ b/conda/environments/all_cuda-132_arch-aarch64.yaml @@ -47,7 +47,7 @@ dependencies: - nltk - numba-cuda>=0.22.2,<0.29.0 - numba>=0.60.0,<0.65.0 -- numpy>=1.23,<3.0 +- numpy>=1.26,<3.0 - numpydoc - numpydoc<1.9 - nvidia-ml-py>=12 diff --git a/conda/environments/all_cuda-132_arch-x86_64.yaml b/conda/environments/all_cuda-132_arch-x86_64.yaml index 2eda3604e5..b879ce0d48 100644 --- a/conda/environments/all_cuda-132_arch-x86_64.yaml +++ b/conda/environments/all_cuda-132_arch-x86_64.yaml @@ -46,7 +46,7 @@ dependencies: - nltk - numba-cuda>=0.22.2,<0.29.0 - numba>=0.60.0,<0.65.0 -- numpy>=1.23,<3.0 +- numpy>=1.26,<3.0 - numpydoc - numpydoc<1.9 - nvidia-ml-py>=12 diff --git a/conda/recipes/cuml/recipe.yaml b/conda/recipes/cuml/recipe.yaml index 2c526f86ca..960d4347df 100644 --- a/conda/recipes/cuml/recipe.yaml +++ b/conda/recipes/cuml/recipe.yaml @@ -100,7 +100,7 @@ requirements: - libcuml =${{ version }} - numba >=0.60.0,<0.65.0 - numba-cuda >=0.22.2,<0.29.0 - - numpy >=1.23,<3.0 + - numpy >=1.26,<3.0 - scikit-learn >=1.4 - scipy >=1.14.0 - packaging diff --git a/dependencies.yaml b/dependencies.yaml index f1d04fec4a..93df8a4de8 100644 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -323,7 +323,7 @@ dependencies: packages: - joblib>=0.11 - numba>=0.60.0,<0.65.0 - - &numpy numpy>=1.23,<3.0 + - &numpy numpy>=1.26,<3.0 - scipy>=1.14.0 - packaging - rich @@ -530,12 +530,15 @@ dependencies: - scikit-learn==1.5.0 - umap-learn==0.5.7 - hdbscan==0.8.39 + - numpy==1.26 + - cupy==13.6 - matrix: {dependencies: "intermediate"} packages: - scikit-learn==1.7.2 - umap-learn==0.5.8 - ipython==8.10.0 - hdbscan==0.8.41 + - numpy==2.0 - matrix: {dependencies: "nightly"} packages: # Pre-release specifier tells pip to accept dev/alpha/beta versions diff --git a/python/cuml/pyproject.toml b/python/cuml/pyproject.toml index 18a5aa8a25..04ae556bb7 100644 --- a/python/cuml/pyproject.toml +++ b/python/cuml/pyproject.toml @@ -87,7 +87,7 @@ dependencies = [ "libcuml==26.6.*,>=0.0.0a0", "numba-cuda>=0.22.2,<0.29.0", "numba>=0.60.0,<0.65.0", - "numpy>=1.23,<3.0", + "numpy>=1.26,<3.0", "nvidia-nvjitlink>=13.0,<14", "packaging", "pylibraft==26.6.*,>=0.0.0a0", From b27eb3039b2a4ae8bfeab68190841ea459135b4f Mon Sep 17 00:00:00 2001 From: Jim Crist-Harif Date: Fri, 15 May 2026 12:07:31 -0500 Subject: [PATCH 2/6] Remove use of numpy 2 apis --- python/cuml/cuml/internals/validation.py | 30 ++++++++++++------- .../cuml/linear_model/linear_regression.pyx | 2 +- python/cuml/cuml/linear_model/ridge.pyx | 2 +- python/cuml/tests/test_validation.py | 5 ++-- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/python/cuml/cuml/internals/validation.py b/python/cuml/cuml/internals/validation.py index 2e00a2c623..5c14cbf36d 100644 --- a/python/cuml/cuml/internals/validation.py +++ b/python/cuml/cuml/internals/validation.py @@ -351,7 +351,7 @@ def check_all_finite(array, *, allow_nan=False, input_name=None) -> None: input_name : str or None, default=None The input parameter name to use in error messages. """ - if not np.isdtype(array.dtype, "real floating"): + if not array.dtype.kind == "f": # No-op for non floating inputs return @@ -484,6 +484,20 @@ def _index_as_mem_type(index, mem_type=None): return index +if np.__version__.startswith("1."): + + def np_asarray(x, dtype=None, order=None, copy=None): + """A compatibility shim for `np.asarray`. + + numpy 2.0 added the `copy` arg to `np.asarray`, as well as changed the + meaning of copy=False to "error if a copy required" rather than "only + copy if needed" (which is now `copy=None`).""" + return np.array(x, dtype=dtype, order=order, copy=bool(copy)) + +else: + np_asarray = np.asarray + + def check_array( array, *, @@ -600,7 +614,7 @@ def check_array( # Infer proper output dtype if array_dtype is not None: # Check for complex inputs before conversion when possible - if np.isdtype(array_dtype, "complex floating"): + if array_dtype.kind == "c": raise ValueError("Complex data not supported") if dtype is None: dtype = array_dtype @@ -703,7 +717,7 @@ def check_array( elif ( mem_type is None and cudf.pandas.LOADED - and np.isdtype(array.dtype, ("numeric", "bool")) + and array.dtype.kind in "iufb" ): # We treat pandas objects with supported dtypes as device # memory when running under cudf.pandas. Note that the output @@ -732,8 +746,7 @@ def check_array( array, dtype=dtype, order=order, copy=(copy or None) ) else: - # XXX: using np.array for compat with numpy < 2 - array = np.array( + array = np_asarray( array, dtype=dtype, order=order, copy=(copy or None) ) @@ -761,7 +774,7 @@ def check_array( ) # Check for complex inputs after conversion for cases when `dtype=None` - if np.isdtype(array.dtype, "complex floating"): + if array.dtype.kind == "c": raise ValueError("Complex data not supported") # Validate data meets expected value requirements @@ -1052,10 +1065,7 @@ def check_y( input_dtype = y.dtype if mem_type is None: mem_type = "host" if isinstance(y, np.ndarray) else "device" - if ( - np.isdtype(y.dtype, ("numeric", "bool")) - and return_classes is True - ): + if y.dtype.kind in "iufb" and return_classes is True: y = cp.asarray(y) elif ( y.dtype == "object" diff --git a/python/cuml/cuml/linear_model/linear_regression.pyx b/python/cuml/cuml/linear_model/linear_regression.pyx index 450db871a1..387a0dd437 100644 --- a/python/cuml/cuml/linear_model/linear_regression.pyx +++ b/python/cuml/cuml/linear_model/linear_regression.pyx @@ -241,7 +241,7 @@ class LinearRegression(Base, ) # All libcuml solvers require F-ordered X, and mutate the inputs. - X = cp.asarray(X, order="F", copy=None if may_mutate_X else True) + X = cp.array(X, order="F", copy=None if may_mutate_X else True) if not may_mutate_y: y = y.copy() if sample_weight is not None and not may_mutate_sample_weight: diff --git a/python/cuml/cuml/linear_model/ridge.pyx b/python/cuml/cuml/linear_model/ridge.pyx index c9e196cbfd..085474e848 100644 --- a/python/cuml/cuml/linear_model/ridge.pyx +++ b/python/cuml/cuml/linear_model/ridge.pyx @@ -285,7 +285,7 @@ class Ridge(Base, # The `eig` solver requires X be F-contiguous. Additionally, all inputs # are mutated when weighted or `fit_intercept=True`. mutates = self.fit_intercept or sample_weight is not None - X = cp.asarray(X, order="F", copy=True if mutates and not may_mutate_X else None) + X = cp.array(X, order="F", copy=True if mutates and not may_mutate_X else None) if mutates and not may_mutate_y: y = y.copy() if sample_weight is not None and mutates and not may_mutate_sample_weight: diff --git a/python/cuml/tests/test_validation.py b/python/cuml/tests/test_validation.py index 7d67d1c603..95a97ca113 100644 --- a/python/cuml/tests/test_validation.py +++ b/python/cuml/tests/test_validation.py @@ -841,8 +841,9 @@ def test_check_array_dataframe_mixed_dtypes(kind, mem_type): ) # Non-numeric columns -> object dtype by default if is_cuda_output(mem_type, df): - # cupy doesn't support object dtypes - with pytest.raises((ValueError, TypeError), match="object"): + # cupy doesn't support object dtypes. We don't care what the exception + # is here, just that one is raised. + with pytest.raises(Exception, match="object"): check_array(df, mem_type=mem_type) else: # dtype=None does no conversion by default From d03231c80560e06e8760565acca3e613bdda6e63 Mon Sep 17 00:00:00 2001 From: Jim Crist-Harif Date: Fri, 15 May 2026 13:27:05 -0500 Subject: [PATCH 3/6] No intermediate dep test --- dependencies.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/dependencies.yaml b/dependencies.yaml index 93df8a4de8..b497f5e0b7 100644 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -538,7 +538,6 @@ dependencies: - umap-learn==0.5.8 - ipython==8.10.0 - hdbscan==0.8.41 - - numpy==2.0 - matrix: {dependencies: "nightly"} packages: # Pre-release specifier tells pip to accept dev/alpha/beta versions From 8dd4f4332fb3a2ed25b5dd7ab464ed77b7fb39c0 Mon Sep 17 00:00:00 2001 From: Jim Crist-Harif Date: Fri, 15 May 2026 13:29:21 -0500 Subject: [PATCH 4/6] Skip some xgb tests on numpy 1.x --- python/cuml/tests/explainer/test_gpu_treeshap.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/python/cuml/tests/explainer/test_gpu_treeshap.py b/python/cuml/tests/explainer/test_gpu_treeshap.py index 3459a30ead..10b27525b7 100644 --- a/python/cuml/tests/explainer/test_gpu_treeshap.py +++ b/python/cuml/tests/explainer/test_gpu_treeshap.py @@ -124,6 +124,9 @@ def count_categorical_split(tl_model): ) def test_xgb_regressor(objective): xgb = pytest.importorskip("xgboost") + pytest.importorskip( + "numpy", minversion="2.0", reason="Test fails on numpy < 2" + ) n_samples = 100 X, y = make_regression( @@ -197,6 +200,9 @@ def test_xgb_regressor(objective): ) def test_xgb_classifier(objective, n_classes): xgb = pytest.importorskip("xgboost") + pytest.importorskip( + "numpy", minversion="2.0", reason="Test fails on numpy < 2" + ) n_samples = 100 X, y = make_classification( From 1c4f4080dedc51fcdd00b3533d0e51896f861999 Mon Sep 17 00:00:00 2001 From: Jim Crist-Harif Date: Fri, 15 May 2026 13:32:04 -0500 Subject: [PATCH 5/6] Fixup --- python/cuml/cuml/internals/validation.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/python/cuml/cuml/internals/validation.py b/python/cuml/cuml/internals/validation.py index 5c14cbf36d..29ac384e43 100644 --- a/python/cuml/cuml/internals/validation.py +++ b/python/cuml/cuml/internals/validation.py @@ -484,7 +484,9 @@ def _index_as_mem_type(index, mem_type=None): return index -if np.__version__.startswith("1."): +if np.lib.NumpyVersion(np.__version__) >= "2.0.0b1": + np_asarray = np.asarray +else: def np_asarray(x, dtype=None, order=None, copy=None): """A compatibility shim for `np.asarray`. @@ -494,9 +496,6 @@ def np_asarray(x, dtype=None, order=None, copy=None): copy if needed" (which is now `copy=None`).""" return np.array(x, dtype=dtype, order=order, copy=bool(copy)) -else: - np_asarray = np.asarray - def check_array( array, From 0f17baccfbf77e4aa19d99002955d57d8957e437 Mon Sep 17 00:00:00 2001 From: Jim Crist-Harif Date: Fri, 15 May 2026 13:52:56 -0500 Subject: [PATCH 6/6] Fixup --- dependencies.yaml | 1 - python/cuml/cuml/internals/validation.py | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/dependencies.yaml b/dependencies.yaml index b497f5e0b7..69dec35112 100644 --- a/dependencies.yaml +++ b/dependencies.yaml @@ -531,7 +531,6 @@ dependencies: - umap-learn==0.5.7 - hdbscan==0.8.39 - numpy==1.26 - - cupy==13.6 - matrix: {dependencies: "intermediate"} packages: - scikit-learn==1.7.2 diff --git a/python/cuml/cuml/internals/validation.py b/python/cuml/cuml/internals/validation.py index 29ac384e43..e8afe0aa55 100644 --- a/python/cuml/cuml/internals/validation.py +++ b/python/cuml/cuml/internals/validation.py @@ -494,7 +494,7 @@ def np_asarray(x, dtype=None, order=None, copy=None): numpy 2.0 added the `copy` arg to `np.asarray`, as well as changed the meaning of copy=False to "error if a copy required" rather than "only copy if needed" (which is now `copy=None`).""" - return np.array(x, dtype=dtype, order=order, copy=bool(copy)) + return np.array(x, dtype=dtype, order=order or "K", copy=bool(copy)) def check_array(