Repository: nilearn/nilearn

Issue:
Relocate functions from datasets.utils
Suggestion to do in a separate PR:
What do you think about deprecating this file and relocating these two functions? `load_sample_motor_activation_image` could go under `func.py`; not so sure yet about `get_data_dirs`. Or alternatively renaming `utils.py`
Not sure if it's worth it but something to think about if any confusion arises from having `_utils.py` and `utils.py`

_Originally posted by @ymzayek in https://github.com/nilearn/nilearn/pull/4086#discussion_r1384846240_
            


Discussion:
move all function in `utils.py` into `_utils.py` ?
Pretty much except for the public functions that we would put into another module with some "redirecting" with a deprecation warning.

Resolving patch:
diff --git a/nilearn/datasets/__init__.py b/nilearn/datasets/__init__.py
--- a/nilearn/datasets/__init__.py
+++ b/nilearn/datasets/__init__.py
@@ -41,6 +41,7 @@
     fetch_spm_auditory,
     fetch_spm_multimodal_fmri,
     fetch_surf_nki_enhanced,
+    load_sample_motor_activation_image,
     patch_openneuro_dataset,
     select_from_index,
 )
@@ -65,7 +66,7 @@
     load_mni152_wm_mask,
     load_mni152_wm_template,
 )
-from .utils import get_data_dirs, load_sample_motor_activation_image
+from .utils import get_data_dirs
 
 __all__ = [
     "MNI152_FILE_PATH",
diff --git a/nilearn/datasets/func.py b/nilearn/datasets/func.py
--- a/nilearn/datasets/func.py
+++ b/nilearn/datasets/func.py
@@ -8,6 +8,7 @@
 import re
 import warnings
 from io import BytesIO
+from pathlib import Path
 
 import nibabel
 import nibabel as nib
@@ -2987,3 +2988,14 @@ def _glob_fiac_data():
         return fetch_fiac_first_level(data_dir=data_dir)
 
     return _glob_fiac_data()
+
+
+def load_sample_motor_activation_image():
+    """Load a single functional image showing motor activations.
+
+    Returns
+    -------
+    str
+        Path to the sample functional image.
+    """
+    return str(Path(__file__).parent / "data" / "image_10426.nii.gz")
diff --git a/nilearn/datasets/utils.py b/nilearn/datasets/utils.py
--- a/nilearn/datasets/utils.py
+++ b/nilearn/datasets/utils.py
@@ -1,9 +1,16 @@
 """Downloading NeuroImaging datasets: utility functions."""
 import os
-from pathlib import Path
+from warnings import warn
 
 from .._utils import fill_doc
 
+_GENERAL_MESSAGE = (
+    "The import path 'nilearn.datasets.utils' "
+    "will deprecated in version 0.13. "
+    "Importing from 'nilearn.datasets.utils will be possible "
+    "at least until release 0.13.0."
+)
+
 
 @fill_doc
 def get_data_dirs(data_dir=None):
@@ -64,4 +71,13 @@ def load_sample_motor_activation_image():
     str
         Path to the sample functional image.
     """
-    return str(Path(__file__).parent / "data" / "image_10426.nii.gz")
+    from .func import load_sample_motor_activation_image as tmp
+
+    warn(
+        (
+            f"{_GENERAL_MESSAGE}"
+            "Please import this function from 'nilearn.datasets.func' instead."
+        ),
+        DeprecationWarning,
+    )
+    return tmp()


Test patch:
diff --git a/nilearn/datasets/tests/test_func.py b/nilearn/datasets/tests/test_func.py
--- a/nilearn/datasets/tests/test_func.py
+++ b/nilearn/datasets/tests/test_func.py
@@ -11,7 +11,6 @@
 from collections import OrderedDict
 from pathlib import Path
 
-import nibabel
 import nibabel as nib
 import numpy as np
 import pandas as pd
@@ -20,6 +19,7 @@
 from nilearn.datasets import func
 from nilearn.datasets._utils import get_dataset_dir
 from nilearn.datasets.tests._testing import dict_to_archive, list_to_archive
+from nilearn.image import load_img
 
 
 def _load_localizer_index():
@@ -390,7 +390,7 @@ def test__load_mixed_gambles(rng, affine_eye):
     n_trials = 48
     for n_subjects in [1, 5, 16]:
         zmaps = [
-            nibabel.Nifti1Image(
+            nib.Nifti1Image(
                 rng.standard_normal((3, 4, 5, n_trials)), affine_eye
             )
             for _ in range(n_subjects)
@@ -1039,3 +1039,10 @@ def test_fiac(tmp_path):
     assert isinstance(dataset.design_matrix1, str)
     assert isinstance(dataset.design_matrix2, str)
     assert isinstance(dataset.mask, str)
+
+
+def test_load_sample_motor_activation_image():
+    path_img = func.load_sample_motor_activation_image()
+
+    assert os.path.exists(path_img)
+    assert load_img(path_img)
diff --git a/nilearn/datasets/tests/test_utils.py b/nilearn/datasets/tests/test_utils.py
--- a/nilearn/datasets/tests/test_utils.py
+++ b/nilearn/datasets/tests/test_utils.py
@@ -16,8 +16,7 @@
 import pytest
 import requests
 
-from nilearn.datasets import _utils, utils
-from nilearn.image import load_img
+from nilearn.datasets import _utils
 
 currdir = os.path.dirname(os.path.abspath(__file__))
 datadir = os.path.join(currdir, "data")
@@ -513,8 +512,13 @@ def test_naive_ftp_adapter():
         )
 
 
-def test_load_sample_motor_activation_image():
-    path_img = utils.load_sample_motor_activation_image()
+# TODO remove for release 0.13.0
+from nilearn.datasets import utils
+
 
-    assert os.path.exists(path_img)
-    assert load_img(path_img)
+def test_load_sample_motor_activation_image():
+    with pytest.warns(
+        DeprecationWarning,
+        match="Please import this function from 'nilearn.datasets.func'",
+    ):
+        utils.load_sample_motor_activation_image()