Coverage for nilearn/_utils/tests/test_numpy_conversions.py: 0%
111 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-20 10:58 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-20 10:58 +0200
1"""Test the numpy_conversions module.
3This test file is in nilearn/tests because Nosetest,
4which we historically used,
5ignores modules whose name starts with an underscore.
6"""
8from pathlib import Path
10import numpy as np
11import pytest
13from nilearn._utils.numpy_conversions import as_ndarray, csv_to_array
16def are_arrays_identical(arr1, arr2):
17 """Check if two 1-dimensional array point to the same buffer.
19 The check is performed only on the first value of the arrays. For
20 this test to be reliable, arr2 must not point to a subset of arr1.
21 For example, if arr2 = arr1[1:] has been executed just before calling
22 this function, the test will FAIL, even if the same buffer is used by
23 both arrays. arr2 = arr1[:1] will succeed though.
25 dtypes are not supposed to be identical.
26 """
27 # Modify the first value in arr1 twice, and see if corresponding
28 # value in arr2 has changed. Changing the value twice is required, since
29 # the original value could be the first value that we use.
31 orig1 = arr1[0]
32 orig2 = arr2[0]
34 arr1[0] = 0
35 if arr2[0] != orig2:
36 arr1[0] = orig1
37 return True
39 arr1[0] = 1
40 if arr2[0] != orig2:
41 arr1[0] = orig1
42 return True
44 arr1[0] = orig1
45 return False
48def test_are_array_identical():
49 arr1 = np.ones(4)
50 orig1 = arr1.copy()
52 arr2 = arr1
53 orig2 = arr2.copy()
55 assert are_arrays_identical(arr1, arr2)
56 np.testing.assert_array_almost_equal(orig1, arr1, decimal=10)
57 np.testing.assert_array_almost_equal(orig2, arr2, decimal=10)
59 arr2 = arr1[:1]
60 orig2 = arr2.copy()
61 assert are_arrays_identical(arr1, arr2)
62 np.testing.assert_array_almost_equal(orig1, arr1, decimal=10)
63 np.testing.assert_array_almost_equal(orig2, arr2, decimal=10)
65 arr2 = arr1[1:]
66 orig2 = arr2.copy()
67 assert not are_arrays_identical(arr1, arr2)
68 np.testing.assert_array_almost_equal(orig1, arr1, decimal=10)
69 np.testing.assert_array_almost_equal(orig2, arr2, decimal=10)
71 arr2 = arr1.copy()
72 orig2 = arr2.copy()
73 assert not are_arrays_identical(arr1, arr2)
74 np.testing.assert_array_almost_equal(orig1, arr1, decimal=10)
75 np.testing.assert_array_almost_equal(orig2, arr2, decimal=10)
78@pytest.mark.parametrize(
79 "input_dtype, input_order, copy, output_dtype, output_order, was_copied",
80 [
81 # no-op
82 (float, "C", False, None, None, False),
83 (float, "F", False, None, None, False),
84 # simple copy
85 (float, "C", True, None, None, True),
86 (float, "F", True, None, None, True),
87 # dtype provided, identical
88 (float, "C", False, float, None, False),
89 (float, "F", False, float, None, False),
90 # dtype changed
91 (float, "C", False, np.float32, None, True),
92 (float, "F", False, np.float32, None, True),
93 # dtype and order provided, but identical
94 (float, "C", False, float, "C", False),
95 (float, "F", False, float, "F", False),
96 # order provided, unchanged
97 (float, "C", False, None, "C", False),
98 (float, "F", False, None, "F", False),
99 (float, "C", True, None, "C", True),
100 (float, "F", True, None, "F", True),
101 # order provided, changed
102 (float, "C", False, None, "F", True),
103 (float, "F", False, None, "C", True),
104 (float, "C", True, None, "F", True),
105 (float, "F", True, None, "C", True),
106 # Special case for int8 <-> bool conversion.
107 (np.int8, "C", False, bool, None, False),
108 (np.int8, "F", False, bool, None, False),
109 (np.int8, "C", False, bool, "C", False),
110 (np.int8, "F", False, bool, "F", False),
111 (np.int8, "C", False, bool, "F", True),
112 (np.int8, "F", False, bool, "C", True),
113 (np.int8, "C", True, bool, None, True),
114 (np.int8, "F", True, bool, None, True),
115 (np.int8, "C", True, bool, "C", True),
116 (np.int8, "F", True, bool, "F", True),
117 (bool, "C", False, np.int8, None, False),
118 (bool, "F", False, np.int8, None, False),
119 (bool, "C", False, np.int8, "C", False),
120 (bool, "F", False, np.int8, "F", False),
121 (bool, "C", False, np.int8, "F", True),
122 (bool, "F", False, np.int8, "C", True),
123 (bool, "C", True, np.int8, None, True),
124 (bool, "F", True, np.int8, None, True),
125 (bool, "C", True, np.int8, "C", True),
126 (bool, "F", True, np.int8, "F", True),
127 ],
128)
129def test_as_ndarray(
130 input_dtype, input_order, copy, output_dtype, output_order, was_copied
131):
132 shape = (10, 11)
133 arr1 = np.ones(shape, dtype=input_dtype, order=input_order)
134 arr2 = as_ndarray(arr1, copy=copy, dtype=output_dtype, order=output_order)
136 # check if nd_array copied the original array or not
137 assert are_arrays_identical(arr1[0], arr2[0]) != was_copied
139 if output_dtype is None:
140 assert arr2.dtype == input_dtype
141 else:
142 assert arr2.dtype == output_dtype
144 result_order = output_order if output_order is not None else input_order
146 if result_order == "F":
147 assert arr2.flags["F_CONTIGUOUS"]
148 else:
149 assert arr2.flags["C_CONTIGUOUS"]
152def test_as_ndarray_memmap():
153 # memmap
154 filename = Path(__file__).parent / "data" / "mmap.dat"
156 # same dtype, no copy requested
157 arr1 = np.memmap(filename, dtype="float32", mode="w+", shape=(5,))
158 arr2 = as_ndarray(arr1)
159 assert not are_arrays_identical(arr1, arr2)
161 # same dtype, copy requested
162 arr1 = np.memmap(filename, dtype="float32", mode="readwrite", shape=(5,))
163 arr2 = as_ndarray(arr1, copy=True)
164 assert not are_arrays_identical(arr1, arr2)
166 # different dtype
167 arr1 = np.memmap(filename, dtype="float32", mode="readwrite", shape=(5,))
168 arr2 = as_ndarray(arr1, dtype=int)
169 assert arr2.dtype == int
170 assert not are_arrays_identical(arr1, arr2)
172 # same dtype, explicitly provided: must copy
173 arr1 = np.memmap(filename, dtype="float32", mode="readwrite", shape=(5,))
174 arr2 = as_ndarray(arr1, dtype=np.float32)
175 assert arr2.dtype == np.float32
176 assert not are_arrays_identical(arr1, arr2)
178 # same dtype, order provided
179 arr1 = np.memmap(
180 filename, dtype="float32", mode="readwrite", shape=(10, 10)
181 )
182 arr2 = as_ndarray(arr1, order="F")
183 assert arr2.flags["F_CONTIGUOUS"] and not arr2.flags["C_CONTIGUOUS"]
184 assert arr2.dtype == arr1.dtype
185 assert not are_arrays_identical(arr1[0], arr2[0])
187 # same dtype, order unchanged but provided
188 arr1 = np.memmap(
189 filename, dtype="float32", mode="readwrite", shape=(10, 10), order="F"
190 )
191 arr2 = as_ndarray(arr1, order="F")
192 assert arr2.flags["F_CONTIGUOUS"] and not arr2.flags["C_CONTIGUOUS"]
193 assert arr2.dtype == arr1.dtype
194 assert not are_arrays_identical(arr1[0], arr2[0])
196 # dtype and order specified
197 arr1 = np.memmap(
198 filename, dtype="float32", mode="readwrite", shape=(10, 10), order="F"
199 )
200 arr2 = as_ndarray(arr1, order="F", dtype=np.int32)
201 assert arr2.flags["F_CONTIGUOUS"] and not arr2.flags["C_CONTIGUOUS"]
202 assert arr2.dtype == np.int32
203 assert not are_arrays_identical(arr1[0], arr2[0])
206def test_as_ndarray_more():
207 # list
208 # same dtype, no copy requested
209 arr1 = [0, 1, 2, 3]
210 arr2 = as_ndarray(arr1)
211 assert not are_arrays_identical(arr1, arr2)
213 # same dtype, copy requested
214 arr1 = [0, 1, 2, 3]
215 arr2 = as_ndarray(arr1, copy=True)
216 assert not are_arrays_identical(arr1, arr2)
218 # different dtype
219 arr1 = [0, 1, 2, 3]
220 arr2 = as_ndarray(arr1, dtype=float)
221 assert arr2.dtype == float
222 assert not are_arrays_identical(arr1, arr2)
224 # order specified
225 arr1 = [[0, 1, 2, 3], [0, 1, 2, 3]]
226 arr2 = as_ndarray(arr1, dtype=float, order="F")
227 assert arr2.dtype == float
228 assert arr2.flags["F_CONTIGUOUS"] and not arr2.flags["C_CONTIGUOUS"]
229 assert not are_arrays_identical(arr1[0], arr2[0])
231 # Unhandled cases
232 with pytest.raises(ValueError):
233 as_ndarray("test_string")
234 with pytest.raises(ValueError):
235 as_ndarray([], order="invalid")
238def test_csv_to_array(tmp_path):
239 # Create a phony CSV file
240 filename = tmp_path / "tmp.csv"
241 with filename.open(mode="w") as fp:
242 fp.write("1.,2.,3.,4.,5.\n")
243 assert np.allclose(
244 csv_to_array(filename), np.asarray([1.0, 2.0, 3.0, 4.0, 5.0])
245 )
246 with pytest.raises(TypeError):
247 csv_to_array(filename, delimiters="?!")