Repository: nilearn/nilearn

Issue:
`'slice_time_ref' not provided` warning, even when provided
https://github.com/nilearn/nilearn/blob/3edbbb88c61477c6115c2b812c4b3f74345a56cf/nilearn/glm/first_level/first_level.py#L1017-L1023

The message on `line 1017` of `nilearn/glm/first_level/first_level.py`, which is triggered when the `slice_time_ref` cannot be inferred, stipulates that `slice_time_ref` is not provided even when it is, in fact. The rest of the code ends up using the value provided by the user, but the warning is confusing as it looks like this:

```
[...]
UserWarning: No bold.json found in BIDS folder in ../bids_dataset/derivatives/fmriprep.
[...]
UserWarning: 'slice_time_ref' not provided and cannot be inferred from metadata.It will be assumed that the slice timing reference is 0.0 percent of the repetition time. If it is not the case it will need to be set manually in the generated list of models.
[...]
UserWarning: 'slice_time_ref' provided (0.5) is different from the value found in the BIDS dataset (0.0). Note this may lead to the wrong model specification.
```




Discussion:
OK I can reproduce this with the following code.

```python
from pathlib import Path

from nilearn._utils.data_gen import (
    create_fake_bids_dataset,
)

from nilearn.glm.first_level import (
    first_level_from_bids,
)

tmp_path = Path() / "tmp"

tmp_path.mkdir(exist_ok=True)

n_sub = 2
n_ses = 2
n_runs = [1, 2]
tasks = ['localizer', 'main']

bids_path = create_fake_bids_dataset(
    base_dir=tmp_path,
    n_sub=n_sub,
    n_ses=n_ses,
    tasks=tasks,
    n_runs=n_runs
)

task_index = 0

space_label = "MNI"


models, m_imgs, m_events, m_confounds = first_level_from_bids(
    dataset_path=bids_path,
    task_label=tasks[task_index],
    space_label=space_label,
    img_filters=[("desc", "preproc")],
    slice_time_ref=0.6,
    verbose=0,
)
```

output

```text
/home/remi/github/nilearn/nilearn/glm/first_level/first_level.py:1017: UserWarning: 'slice_time_ref' not provided and cannot be inferred from metadata.It will be assumed that the slice timing reference is 0.0 percent of the repetition time. If it is not the case it will need to be set manually in the generated list of models.
  warn("'slice_time_ref' not provided "
/home/remi/github/nilearn/nilearn/glm/first_level/first_level.py:1029: UserWarning: 'slice_time_ref' provided (0.6) is different from the value found in the BIDS dataset (0.0).
Note this may lead to the wrong model specification.
  warn(f"'slice_time_ref' provided ({slice_time_ref}) is different "
```

I must have messed up something in the logic of the "warning throwing".

Also the second warning should probably not be thrown in my example as the data as no slice timing info so it cannot conflict with the one provide by the user.

Should also probably improve the output of those warning to make them more readable.

Resolving patch:
diff --git a/nilearn/glm/first_level/first_level.py b/nilearn/glm/first_level/first_level.py
--- a/nilearn/glm/first_level/first_level.py
+++ b/nilearn/glm/first_level/first_level.py
@@ -990,7 +990,7 @@ def first_level_from_bids(dataset_path,
     if t_r is not None:
         _check_repetition_time(t_r)
     else:
-        warn("'t_r' not provided and cannot be inferred from BIDS metadata. "
+        warn("'t_r' not provided and cannot be inferred from BIDS metadata.\n"
              "It will need to be set manually in the list of models, "
              "otherwise their fit will throw an exception.")
 
@@ -1015,12 +1015,13 @@ def first_level_from_bids(dataset_path,
         assert (StartTime < t_r)
         inferred_slice_time_ref = StartTime / t_r
     else:
-        warn("'slice_time_ref' not provided "
-             "and cannot be inferred from metadata."
-             "It will be assumed that the slice timing reference "
-             "is 0.0 percent of the repetition time. "
-             "If it is not the case it will need to "
-             "be set manually in the generated list of models.")
+        if slice_time_ref is None:
+            warn("'slice_time_ref' not provided "
+                 "and cannot be inferred from metadata.\n"
+                 "It will be assumed that the slice timing reference "
+                 "is 0.0 percent of the repetition time.\n"
+                 "If it is not the case it will need to "
+                 "be set manually in the generated list of models.")
         inferred_slice_time_ref = 0.0
 
     if slice_time_ref is None and inferred_slice_time_ref is not None:


Test patch:
diff --git a/nilearn/glm/tests/test_first_level.py b/nilearn/glm/tests/test_first_level.py
--- a/nilearn/glm/tests/test_first_level.py
+++ b/nilearn/glm/tests/test_first_level.py
@@ -1420,10 +1420,12 @@ def test_first_level_from_bids_no_tr(tmp_path_factory):
         os.remove(f)
 
     with pytest.warns(
-         UserWarning,
-         match="t_r.* will need to be set manually in the list of models"):
+            UserWarning,
+            match="'t_r' not provided and cannot be inferred"):
         first_level_from_bids(
-            dataset_path=bids_dataset, task_label="main", space_label="MNI",
+            dataset_path=bids_dataset,
+            task_label="main",
+            space_label="MNI",
             slice_time_ref=None, t_r=None
         )
 
@@ -1578,3 +1580,21 @@ def test_first_level_from_bids_deprecated_slice_time_default(bids_dataset):
             img_filters=[("desc", "preproc")],
             slice_time_ref=0,
         )
+
+
+def test_slice_time_ref_warning_only_when_not_provided(bids_dataset):
+
+    # catch all warnings
+    with pytest.warns() as record:
+        models, m_imgs, m_events, m_confounds = first_level_from_bids(
+            dataset_path=bids_dataset,
+            task_label="main",
+            space_label="MNI",
+            img_filters=[("desc", "preproc")],
+            slice_time_ref=0.6,
+            verbose=0,
+        )
+
+    # check that no warnings were raised
+    for r in record:
+        assert "'slice_time_ref' not provided" not in r.message.args[0]