Skip to content

Commit 70ab2a6

Browse files
stefanvjnilagru
authored
Allow read-only arrays as input to remap (scikit-image#7535)
In `skimage.util.map_array`, allow read-only arrays (`WRITEABLE` flag set to `False`) as input to the parameters `input_arr`, `input_vals`, and `output_vals`. Closes scikit-image#6378. We should probably add consts across a much larger portion of our Cython code, but this PR illustrates how it can be done. --------- Co-authored-by: Juan Nunez-Iglesias <jni@fastmail.com> Co-authored-by: Lars Grüter <lagru@mailbox.org>
1 parent 5d0aded commit 70ab2a6

File tree

5 files changed

+40
-6
lines changed

5 files changed

+40
-6
lines changed

environment.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ dependencies:
1414
# build
1515
- meson-python>=0.16
1616
- ninja>=1.11.1.1
17-
- Cython>=3.0.8,!=3.2.0b1
17+
- Cython>=3.0.10,!=3.2.0b1
1818
- pythran>=0.16
1919
- numpy>=2.0
2020
- spin==0.13

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ build = [
4848
# Also update [build-system] -> requires
4949
'meson-python>=0.16',
5050
'ninja>=1.11.1.1',
51-
'Cython>=3.0.8,!=3.2.0b1',
51+
'Cython>=3.0.10,!=3.2.0b1',
5252
'pythran>=0.16',
5353
'numpy>=2.0',
5454
# Developer UI
@@ -124,7 +124,7 @@ tracker = 'https://github.com/scikit-image/scikit-image/issues'
124124
build-backend = 'mesonpy'
125125
requires = [
126126
'meson-python>=0.16',
127-
'Cython>=3.0.8,!=3.2.0b1',
127+
'Cython>=3.0.10,!=3.2.0b1',
128128
'pythran>=0.16',
129129
'lazy_loader>=0.4',
130130
'numpy>=2.0',

requirements/build.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
# Do not edit this file; modify pyproject.toml instead.
33
meson-python>=0.16
44
ninja>=1.11.1.1
5-
Cython>=3.0.8,!=3.2.0b1
5+
Cython>=3.0.10,!=3.2.0b1
66
pythran>=0.16
77
numpy>=2.0
88
spin==0.13

src/skimage/util/_remap.pyx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ from .._shared.fused_numerics cimport np_numeric, np_anyint
77

88
@cython.boundscheck(False) # Deactivate bounds checking
99
@cython.wraparound(False) # Deactivate negative indexing
10-
def _map_array(np_anyint[:] inarr, np_numeric[:] outarr,
11-
np_anyint[:] inval, np_numeric[:] outval):
10+
def _map_array(const np_anyint[:] inarr, np_numeric[:] outarr,
11+
const np_anyint[:] inval, const np_numeric[:] outval):
1212
# build the map from the input and output vectors
1313
cdef size_t i, n_map, n_array
1414
cdef unordered_map[np_anyint, np_numeric] lut

tests/skimage/util/test_map_array.py

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import itertools
2+
13
import numpy as np
24
import pytest
35
from skimage.util._map_array import map_array, ArrayMap
@@ -39,6 +41,38 @@ def test_map_array_simple(dtype_in, dtype_out, out_array):
3941
assert out is result
4042

4143

44+
@pytest.mark.parametrize("writeable_flags", itertools.product([True, False], repeat=3))
45+
@pytest.mark.parametrize("dtype", _map_array_dtypes_in)
46+
def test_map_array_read_only(writeable_flags, dtype):
47+
"""Check that input arrays can be read-only, but output_arr must not be.
48+
49+
See https://github.com/scikit-image/scikit-image/issues/6378.
50+
"""
51+
input_arr = np.array([0, 2, 0, 3, 4, 5, 0], dtype=dtype)
52+
input_vals = np.array([1, 2, 3, 4, 6], dtype=dtype)
53+
output_vals = np.array([6, 7, 8, 9, 10], dtype=dtype)
54+
out = np.full(input_arr.shape, 11, dtype=dtype)
55+
desired = np.array([0, 7, 0, 8, 9, 0, 0], dtype=dtype)
56+
57+
for arr, writeable in zip(
58+
[input_arr, input_vals, output_vals], writeable_flags, strict=True
59+
):
60+
arr.flags.writeable = writeable
61+
62+
# this should run without error
63+
result = map_array(
64+
input_arr=input_arr, input_vals=input_vals, output_vals=output_vals, out=out
65+
)
66+
np.testing.assert_array_equal(result, desired)
67+
68+
# but when out is read-only, it should fail
69+
out.flags.writeable = False
70+
with pytest.raises(ValueError, match="read-only"):
71+
_ = map_array(
72+
input_arr=input_arr, input_vals=input_vals, output_vals=output_vals, out=out
73+
)
74+
75+
4276
def test_map_array_incorrect_output_shape():
4377
labels = np.random.randint(0, 5, size=(24, 25))
4478
out = np.empty((24, 24))

0 commit comments

Comments
 (0)