Repository: aramis-lab/clinica

Issue:
[REF][TEST] OASIS-to-BIDS : logic for finding `.img` files can be moved from `_converter` to `_utils` and tested
In OASIS-to-BIDS `_converter` module, the following lines of code could be moved out in an appropriate function in the `_utils` module.

https://github.com/aramis-lab/clinica/blob/8180aef7a08c561fe7ad39a9dd589013008d42b6/clinica/converters/oasis_to_bids/_converter.py#L174-L179

This could allow to test the behavior of these lines which is not done currently.

Discussion:

Solution patch:
diff --git a/clinica/converters/ixi_to_bids/_utils.py b/clinica/converters/ixi_to_bids/_utils.py
index 19848703..1f312b3c 100644
--- a/clinica/converters/ixi_to_bids/_utils.py
+++ b/clinica/converters/ixi_to_bids/_utils.py
@@ -365,9 +365,14 @@ def write_sessions(
     clinical_data : Dataframe containing the formatted clinical data of the IXI study.
     participant : Current converted subject study id (str).
     """
-    line = clinical_data[clinical_data["source_id"] == participant]
+    to_write = clinical_data[clinical_data["source_id"] == participant][
+        ["source_id", "session_id", "acq_time"]
+    ]
+    if to_write.empty:
+        to_write.loc[0, "source_id"] = participant
+        to_write.fillna("n/a", inplace=True)
     bids_id = bids_id_factory(StudyName.IXI).from_original_study_id(participant)
-    line[["source_id", "session_id", "acq_time"]].to_csv(
+    to_write.to_csv(
         bids_dir / bids_id / f"{bids_id}_sessions.tsv", sep="\t", index=False
     )
 
diff --git a/clinica/converters/oasis_to_bids/_converter.py b/clinica/converters/oasis_to_bids/_converter.py
index 5cd44044..6b1c4418 100644
--- a/clinica/converters/oasis_to_bids/_converter.py
+++ b/clinica/converters/oasis_to_bids/_converter.py
@@ -155,6 +155,8 @@ class OasisToBids(Converter):
         from clinica.converters.study_models import StudyName, bids_id_factory
         from clinica.utils.stream import cprint
 
+        from ._utils import get_first_image
+
         # This function is executed in a multiprocessing context
         # such that we need to re-configure the clinica logger in the child processes.
         # Note that logging messages could easily be lost (for example when logging
@@ -173,15 +175,10 @@ class OasisToBids(Converter):
         session_folder = bids_subj_folder / "ses-M000"
         if not session_folder.is_dir():
             (session_folder / "anat").mkdir(parents=True, exist_ok=True)
+
         # In order do convert the Analyze format to Nifti the path to the .img file is required
-        try:
-            img_file_path = next(t1_folder.glob("*.img"))
-        except StopIteration:
-            msg = f"No file ending in .img found in {t1_folder}."
-            cprint(msg, lvl="error")
-            raise FileNotFoundError(msg)
         nb.save(
-            _get_image_with_good_orientation(img_file_path),
+            _get_image_with_good_orientation(get_first_image(t1_folder)),
             session_folder / "anat" / f"{participant_id}_ses-M000_T1w.nii.gz",
         )
 
diff --git a/clinica/converters/oasis_to_bids/_utils.py b/clinica/converters/oasis_to_bids/_utils.py
index b76990da..ceb666d6 100644
--- a/clinica/converters/oasis_to_bids/_utils.py
+++ b/clinica/converters/oasis_to_bids/_utils.py
@@ -5,7 +5,12 @@ import pandas as pd
 
 from clinica.converters.study_models import StudyName, bids_id_factory
 
-__all__ = ["create_sessions_df", "write_sessions_tsv", "write_scans_tsv"]
+__all__ = [
+    "create_sessions_df",
+    "write_sessions_tsv",
+    "write_scans_tsv",
+    "get_first_image",
+]
 
 
 def _convert_cdr_to_diagnosis(cdr: Union[int, str]) -> str:
@@ -133,3 +138,30 @@ def write_scans_tsv(bids_dir: Path) -> None:
                 sep="\t",
                 index=False,
             )
+
+
+def get_first_image(input_folder: Path) -> Path:
+    """Get the first .img file in the folder given as parameter.
+    Throw an exception if no file is found.
+
+    Parameters
+    ----------
+    input_folder : Path
+        The path to the input folder.
+
+    Returns
+    -------
+    Path :
+        The path to the first image found in the provided folder.
+    """
+    from clinica.utils.stream import log_and_raise
+
+    try:
+        img_file_path = next(input_folder.glob("*.img"))
+        return img_file_path
+
+    except StopIteration:
+        log_and_raise(
+            f"No file ending in .img found in {input_folder}.",
+            FileNotFoundError,
+        )


Test patch:
diff --git a/test/nonregression/test_run_converters.py b/test/nonregression/test_run_converters.py
index efd5998c..96635ac3 100644
--- a/test/nonregression/test_run_converters.py
+++ b/test/nonregression/test_run_converters.py
@@ -35,5 +35,5 @@ def test_converters(cmdopt, tmp_path, study: StudyName):
     )
 
     compare_folders(output_dir, ref_dir / "bids", output_dir)
-    if study == StudyName.AIBL:
+    if study in (StudyName.AIBL, StudyName.IXI):
         compare_bids_tsv(output_dir, ref_dir / "bids")
diff --git a/test/unittests/converters/test_oasis_to_bids_utils.py b/test/unittests/converters/test_oasis_to_bids_utils.py
index 710ff4ce..d550980e 100644
--- a/test/unittests/converters/test_oasis_to_bids_utils.py
+++ b/test/unittests/converters/test_oasis_to_bids_utils.py
@@ -243,6 +243,32 @@ def test_write_scans_tsv(tmp_path, bids_dir: Path) -> None:
                 assert file.empty
 
 
+def test_get_first_image(tmp_path: Path) -> None:
+    from clinica.converters.oasis_to_bids._utils import get_first_image
+
+    folder_path = tmp_path / "folder"
+
+    (folder_path).mkdir()
+    (folder_path / "file_1.txt").touch()
+    (folder_path / "file_2.img").touch()
+
+    assert get_first_image(folder_path) == (folder_path / "file_2.img")
+
+
+def test_get_first_image_not_found_error(tmp_path: Path) -> None:
+    from clinica.converters.oasis_to_bids._utils import get_first_image
+
+    folder_path = tmp_path / "folder"
+
+    (folder_path).mkdir()
+    (folder_path / "file.txt").touch()
+
+    with pytest.raises(
+        FileNotFoundError, match=f"No file ending in .img found in {folder_path}."
+    ):
+        get_first_image(folder_path)
+
+
 @pytest.mark.parametrize(
     "cdr,diagnosis",
     [