diff --git a/setup.py b/setup.py index 2ac07ec44c947..21734a8eeddba 100755 --- a/setup.py +++ b/setup.py @@ -120,7 +120,6 @@ "sklearn.utils._logistic_sigmoid", "sklearn.utils._openmp_helpers", "sklearn.utils._random", - "sklearn.utils._readonly_array_wrapper", "sklearn.utils._seq_dataset", "sklearn.utils._sorting", "sklearn.utils._typedefs", @@ -455,7 +454,6 @@ def check_package_status(package, min_version): }, {"sources": ["_random.pyx"], "include_np": True}, {"sources": ["_logistic_sigmoid.pyx"], "include_np": True}, - {"sources": ["_readonly_array_wrapper.pyx"], "include_np": True}, {"sources": ["_typedefs.pyx"], "include_np": True}, {"sources": ["_heap.pyx"], "include_np": True}, {"sources": ["_sorting.pyx"], "include_np": True}, diff --git a/sklearn/utils/_readonly_array_wrapper.pyx b/sklearn/utils/_readonly_array_wrapper.pyx deleted file mode 100644 index 95845437db12e..0000000000000 --- a/sklearn/utils/_readonly_array_wrapper.pyx +++ /dev/null @@ -1,67 +0,0 @@ -""" -ReadonlyArrayWrapper implements the buffer protocol to make the wrapped buffer behave as if -writeable, even for readonly buffers. This way, even readonly arrays can be passed as -argument of type (non const) memoryview. -This is a workaround for the missing support for const fused-typed memoryviews in -Cython < 3.0. - -Note: All it does is LIE about the readonly attribute: tell it's false! -This way, we can use it on arrays that we don't touch. -!!! USE CAREFULLY !!! -""" -# TODO: Remove with Cython >= 3.0 which supports const memoryviews for fused types. - -from cpython cimport Py_buffer -from cpython.buffer cimport PyObject_GetBuffer, PyBuffer_Release, PyBUF_WRITABLE - -cimport numpy as cnp - - -cnp.import_array() - - -ctypedef fused NUM_TYPES: - cnp.npy_float64 - cnp.npy_float32 - cnp.npy_int64 - cnp.npy_int32 - - -cdef class ReadonlyArrayWrapper: - cdef object wraps - - def __init__(self, wraps): - self.wraps = wraps - - def __getbuffer__(self, Py_buffer *buffer, int flags): - request_for_writeable = False - if flags & PyBUF_WRITABLE: - flags ^= PyBUF_WRITABLE - request_for_writeable = True - PyObject_GetBuffer(self.wraps, buffer, flags) - if request_for_writeable: - # The following is a lie when self.wraps is readonly! - buffer.readonly = False - - def __releasebuffer__(self, Py_buffer *buffer): - PyBuffer_Release(buffer) - - -def _test_sum(NUM_TYPES[::1] x): - """This function is for testing only. - - As this function does not modify x, we would like to define it as - - _test_sum(const NUM_TYPES[::1] x) - - which is not possible as fused typed const memoryviews aren't - supported in Cython<3.0. - """ - cdef: - int i - int n = x.shape[0] - NUM_TYPES sum = 0 - - for i in range(n): - sum += x[i] - return sum diff --git a/sklearn/utils/tests/test_readonly_wrapper.py b/sklearn/utils/tests/test_readonly_wrapper.py deleted file mode 100644 index 38163cc2461ce..0000000000000 --- a/sklearn/utils/tests/test_readonly_wrapper.py +++ /dev/null @@ -1,41 +0,0 @@ -import numpy as np - -import pytest - -from sklearn.utils._readonly_array_wrapper import ReadonlyArrayWrapper, _test_sum -from sklearn.utils._testing import create_memmap_backed_data - - -def _readonly_array_copy(x): - """Return a copy of x with flag writeable set to False.""" - y = x.copy() - y.flags["WRITEABLE"] = False - return y - - -def _create_memmap_backed_data(data): - return create_memmap_backed_data( - data, mmap_mode="r", return_folder=False, aligned=True - ) - - -@pytest.mark.parametrize("readonly", [_readonly_array_copy, _create_memmap_backed_data]) -@pytest.mark.parametrize("dtype", [np.float32, np.float64, np.int32, np.int64]) -def test_readonly_array_wrapper(readonly, dtype): - """Test that ReadonlyWrapper allows working with fused-typed.""" - x = np.arange(10).astype(dtype) - sum_origin = _test_sum(x) - - # ReadonlyArrayWrapper works with writable buffers - sum_writable = _test_sum(ReadonlyArrayWrapper(x)) - assert sum_writable == pytest.approx(sum_origin, rel=1e-11) - - # Now, check on readonly buffers - x_readonly = readonly(x) - - with pytest.raises(ValueError, match="buffer source array is read-only"): - _test_sum(x_readonly) - - x_readonly = ReadonlyArrayWrapper(x_readonly) - sum_readonly = _test_sum(x_readonly) - assert sum_readonly == pytest.approx(sum_origin, rel=1e-11) diff --git a/sklearn/utils/tests/test_testing.py b/sklearn/utils/tests/test_testing.py index 93c62de0ffa3b..ab959c75350ff 100644 --- a/sklearn/utils/tests/test_testing.py +++ b/sklearn/utils/tests/test_testing.py @@ -11,7 +11,6 @@ from sklearn.utils.deprecation import deprecated from sklearn.utils.metaestimators import available_if, if_delegate_has_method -from sklearn.utils._readonly_array_wrapper import _test_sum from sklearn.utils._testing import ( assert_raises, assert_no_warnings, @@ -680,26 +679,6 @@ def test_create_memmap_backed_data(monkeypatch, aligned): create_memmap_backed_data([input_array, "not-an-array"], aligned=True) -@pytest.mark.parametrize("dtype", [np.float32, np.float64, np.int32, np.int64]) -def test_memmap_on_contiguous_data(dtype): - """Test memory mapped array on contiguous memoryview.""" - x = np.arange(10).astype(dtype) - assert x.flags["C_CONTIGUOUS"] - assert x.flags["ALIGNED"] - - # _test_sum consumes contiguous arrays - # def _test_sum(NUM_TYPES[::1] x): - sum_origin = _test_sum(x) - - # now on memory mapped data - # aligned=True so avoid https://github.com/joblib/joblib/issues/563 - # without alignment, this can produce segmentation faults, see - # https://github.com/scikit-learn/scikit-learn/pull/21654 - x_mmap = create_memmap_backed_data(x, mmap_mode="r+", aligned=True) - sum_mmap = _test_sum(x_mmap) - assert sum_mmap == pytest.approx(sum_origin, rel=1e-11) - - @pytest.mark.parametrize( "constructor_name, container_type", [