Coverage for nilearn/_utils/tests/test_helpers.py: 0%
88 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
1import warnings
2from pathlib import Path
3from unittest.mock import patch
5import pytest
7from nilearn._utils.helpers import (
8 _warn_deprecated_params,
9 compare_version,
10 is_kaleido_installed,
11 is_matplotlib_installed,
12 is_plotly_installed,
13 rename_parameters,
14 set_mpl_backend,
15 stringify_path,
16 transfer_deprecated_param_vals,
17)
18from nilearn._utils.testing import on_windows_with_old_mpl_and_new_numpy
21def _mock_args_for_testing_replace_parameter():
22 """Create mock deprecated & replacement parameters for use \
23 with testing functions related to replace_parameters().
24 """
25 mock_kwargs_with_deprecated_params_used = {
26 "unchanged_param_0": "unchanged_param_0_val",
27 "deprecated_param_0": "deprecated_param_0_val",
28 "deprecated_param_1": "deprecated_param_1_val",
29 "unchanged_param_1": "unchanged_param_1_val",
30 }
31 replacement_params = {
32 "deprecated_param_0": "replacement_param_0",
33 "deprecated_param_1": "replacement_param_1",
34 }
35 return mock_kwargs_with_deprecated_params_used, replacement_params
38@pytest.mark.skipif(
39 on_windows_with_old_mpl_and_new_numpy(),
40 reason="Old matplotlib not compatible with numpy 2.0 on windows.",
41)
42@pytest.mark.skipif(
43 is_matplotlib_installed(),
44 reason="Test requires matplotlib not to be installed.",
45)
46def test_should_raise_custom_warning_if_mpl_not_installed():
47 """Tests if, when provided, custom message is displayed together with
48 default warning.
49 """
50 warning = "This package requires nilearn.plotting package."
51 with (
52 pytest.warns(UserWarning, match=warning + "\nSome dependencies"),
53 pytest.raises(
54 ModuleNotFoundError, match="No module named 'matplotlib'"
55 ),
56 ):
57 set_mpl_backend(warning)
60@pytest.mark.skipif(
61 on_windows_with_old_mpl_and_new_numpy(),
62 reason="Old matplotlib not compatible with numpy 2.0 on windows.",
63)
64@pytest.mark.skipif(
65 is_matplotlib_installed(),
66 reason="Test requires matplotlib not to be installed.",
67)
68def test_should_raise_warning_if_mpl_not_installed():
69 """Tests if default warning is displayed when no custom message is
70 specified.
71 """
72 with (
73 pytest.warns(
74 UserWarning, match="Some dependencies of nilearn.plotting"
75 ),
76 pytest.raises(
77 ModuleNotFoundError, match="No module named 'matplotlib'"
78 ),
79 ):
80 set_mpl_backend()
83@pytest.mark.skipif(
84 not is_matplotlib_installed(),
85 reason="Test requires matplotlib to be installed.",
86)
87@patch("matplotlib.use")
88@patch("matplotlib.get_backend", side_effect=["backend_1", "backend_2"])
89def test_should_raise_warning_if_backend_changes(*_):
90 # The backend values returned by matplotlib.get_backend are different.
91 # Warning should be raised to inform user of the backend switch.
92 with pytest.warns(UserWarning, match="Backend changed to backend_2..."):
93 set_mpl_backend()
96@pytest.mark.skipif(
97 not is_matplotlib_installed(),
98 reason="Test requires matplotlib to be installed.",
99)
100@patch("matplotlib.use")
101@patch("matplotlib.get_backend", side_effect=["backend_1", "backend_1"])
102def test_should_not_raise_warning_if_backend_is_not_changed(*_):
103 # The backend values returned by matplotlib.get_backend are identical.
104 # Warning should not be raised.
105 with warnings.catch_warnings():
106 warnings.simplefilter("error")
107 set_mpl_backend()
110@pytest.mark.skipif(
111 not is_matplotlib_installed(),
112 reason="Test requires matplotlib to be installed.",
113)
114@patch(
115 "matplotlib.use", side_effect=[Exception("Failed to switch backend"), True]
116)
117def test_should_switch_to_agg_backend_if_current_backend_fails(use_mock):
118 # First call to `matplotlib.use` raises an exception, hence the default Agg
119 # backend should be triggered
120 set_mpl_backend()
122 assert use_mock.call_count == 2
123 # Check that the most recent call to `matplotlib.use` has arg `Agg`
124 use_mock.assert_called_with("Agg")
127@pytest.mark.skipif(
128 not is_matplotlib_installed(),
129 reason="Test requires matplotlib to be installed.",
130)
131@patch("matplotlib.__version__", "0.0.0")
132def test_should_raise_import_error_for_version_check():
133 with pytest.raises(ImportError, match="A matplotlib version of at least"):
134 set_mpl_backend()
137def test_rename_parameters():
138 """Test deprecated mock parameters in a mock function.
140 Checks that the deprecated parameters transfer their values correctly
141 to replacement parameters and all deprecation warning are raised as
142 expected.
143 """
144 mock_input, replacement_params = _mock_args_for_testing_replace_parameter()
145 expected_output = ("dp0", "dp1", "up0", "up1")
146 expected_warnings = [
147 (
148 'The parameter "deprecated_param_0" will be removed in 0.6.1rc '
149 "release of other_lib. "
150 'Please use the parameter "replacement_param_0" instead.'
151 ),
152 (
153 'The parameter "deprecated_param_1" will be removed in 0.6.1rc '
154 "release of other_lib. "
155 'Please use the parameter "replacement_param_1" instead.'
156 ),
157 ]
159 @rename_parameters(
160 replacement_params,
161 "0.6.1rc",
162 "other_lib",
163 )
164 def mock_function(
165 replacement_param_0,
166 replacement_param_1,
167 unchanged_param_0,
168 unchanged_param_1,
169 ):
170 return (
171 replacement_param_0,
172 replacement_param_1,
173 unchanged_param_0,
174 unchanged_param_1,
175 )
177 with warnings.catch_warnings(record=True) as raised_warnings:
178 actual_output = mock_function(
179 deprecated_param_0="dp0",
180 deprecated_param_1="dp1",
181 unchanged_param_0="up0",
182 unchanged_param_1="up1",
183 )
185 assert actual_output == expected_output
187 expected_warnings.sort()
188 raised_warnings.sort(key=lambda mem: str(mem.message))
189 for raised_warning_, expected_warning_ in zip(
190 raised_warnings, expected_warnings
191 ):
192 assert raised_warning_.category is DeprecationWarning
193 assert str(raised_warning_.message) == expected_warning_
196def test_transfer_deprecated_param_vals():
197 """Check that values assigned to deprecated parameters are \
198 correctly reassigned to the replacement parameters.
199 """
200 mock_input, replacement_params = _mock_args_for_testing_replace_parameter()
201 expected_output = {
202 "unchanged_param_0": "unchanged_param_0_val",
203 "replacement_param_0": "deprecated_param_0_val",
204 "replacement_param_1": "deprecated_param_1_val",
205 "unchanged_param_1": "unchanged_param_1_val",
206 }
207 actual_output = transfer_deprecated_param_vals(
208 replacement_params,
209 mock_input,
210 )
211 assert actual_output == expected_output
214def test_future_warn_deprecated_params():
215 """Check that the correct warning is displayed."""
216 mock_input, replacement_params = _mock_args_for_testing_replace_parameter()
217 expected_warnings = [
218 (
219 'The parameter "deprecated_param_0" will be removed in sometime '
220 "release of somelib. "
221 'Please use the parameter "replacement_param_0" instead.'
222 ),
223 (
224 'The parameter "deprecated_param_1" will be removed in sometime '
225 "release of somelib. "
226 'Please use the parameter "replacement_param_1" instead.'
227 ),
228 ]
229 with warnings.catch_warnings(record=True) as raised_warnings:
230 _warn_deprecated_params(
231 replacement_params,
232 end_version="sometime",
233 lib_name="somelib",
234 kwargs=mock_input,
235 )
236 expected_warnings.sort()
237 raised_warnings.sort(key=lambda mem: str(mem.message))
238 for raised_warning_, expected_warning_ in zip(
239 raised_warnings, expected_warnings
240 ):
241 assert raised_warning_.category is DeprecationWarning
242 assert str(raised_warning_.message) == expected_warning_
245@pytest.mark.parametrize(
246 "version_a,operator,version_b",
247 [
248 ("0.1.0", ">", "0.0.1"),
249 ("0.1.0", ">=", "0.0.1"),
250 ("0.1", "==", "0.1.0"),
251 ("0.0.0", "<", "0.1.0"),
252 ("1.0", "!=", "0.1.0"),
253 ],
254)
255def test_compare_version(version_a, operator, version_b):
256 assert compare_version(version_a, operator, version_b)
259def test_compare_version_error():
260 with pytest.raises(
261 ValueError,
262 match="'compare_version' received an unexpected operator <>.",
263 ):
264 compare_version("0.1.0", "<>", "1.1.0")
267def test_is_plotly_installed():
268 is_plotly_installed()
271def test_is_kaleido_installed():
272 is_kaleido_installed()
275def test_stringify_path():
276 assert isinstance(stringify_path(Path("foo") / "bar"), str)
277 assert stringify_path([]) == []