diff --git a/clinica/pipelines/anatomical/freesurfer/longitudinal/correction/pipeline.py b/clinica/pipelines/anatomical/freesurfer/longitudinal/correction/pipeline.py index 67db62b2a..3fa7114da 100644 --- a/clinica/pipelines/anatomical/freesurfer/longitudinal/correction/pipeline.py +++ b/clinica/pipelines/anatomical/freesurfer/longitudinal/correction/pipeline.py @@ -60,7 +60,10 @@ def _build_input_node(self): ) from clinica.utils.exceptions import ClinicaException from clinica.utils.input_files import T1_FS_DESTRIEUX, T1_FS_T_DESTRIEUX - from clinica.utils.inputs import _format_errors, clinica_file_reader + from clinica.utils.inputs import ( + clinica_file_reader, + format_clinica_file_reader_errors, + ) from clinica.utils.stream import cprint from .utils import ( @@ -128,7 +131,7 @@ def _build_input_node(self): if any(all_errors): message = "Clinica faced errors while trying to read files in your CAPS directory.\n" for error, info in zip(all_errors, [T1_FS_DESTRIEUX, T1_FS_T_DESTRIEUX]): - message += _format_errors(error, info) + message += format_clinica_file_reader_errors(error, info) raise ClinicaException(message) save_part_sess_long_ids_to_tsv( diff --git a/clinica/pipelines/machine_learning_spatial_svm/spatial_svm_pipeline.py b/clinica/pipelines/machine_learning_spatial_svm/spatial_svm_pipeline.py index e5c79b46d..546dd3c2f 100644 --- a/clinica/pipelines/machine_learning_spatial_svm/spatial_svm_pipeline.py +++ b/clinica/pipelines/machine_learning_spatial_svm/spatial_svm_pipeline.py @@ -64,9 +64,9 @@ def _build_input_node(self): t1_volume_final_group_template, ) from clinica.utils.inputs import ( - _format_errors, clinica_file_reader, clinica_group_reader, + format_clinica_file_reader_errors, ) from clinica.utils.ux import print_groups_in_caps_directory @@ -129,7 +129,9 @@ def _build_input_node(self): caps_files_information, ) if caps_error: - all_errors.append(_format_errors(caps_error, caps_files_information)) + all_errors.append( + format_clinica_file_reader_errors(caps_error, caps_files_information) + ) try: dartel_input = clinica_group_reader( diff --git a/clinica/pipelines/pet/linear/pipeline.py b/clinica/pipelines/pet/linear/pipeline.py index c604307f6..ea9decc38 100644 --- a/clinica/pipelines/pet/linear/pipeline.py +++ b/clinica/pipelines/pet/linear/pipeline.py @@ -67,7 +67,10 @@ def _build_input_node(self): ) from clinica.utils.image import get_mni_template from clinica.utils.input_files import T1W_NII, T1W_TO_MNI_TRANSFORM - from clinica.utils.inputs import _format_errors, clinica_file_reader + from clinica.utils.inputs import ( + clinica_file_reader, + format_clinica_file_reader_errors, + ) from clinica.utils.stream import cprint from clinica.utils.ux import print_images_to_process @@ -83,7 +86,9 @@ def _build_input_node(self): ) if pet_errors: raise ClinicaBIDSError( - _format_errors(pet_errors, self._get_pet_scans_query()) + format_clinica_file_reader_errors( + pet_errors, self._get_pet_scans_query() + ) ) # T1w file: @@ -91,7 +96,9 @@ def _build_input_node(self): self.subjects, self.sessions, self.bids_directory, T1W_NII ) if t1w_errors: - raise ClinicaBIDSError(_format_errors(t1w_errors, T1W_NII)) + raise ClinicaBIDSError( + format_clinica_file_reader_errors(t1w_errors, T1W_NII) + ) # Inputs from t1-linear pipeline # Transformation files from T1w files to MNI: @@ -100,7 +107,9 @@ def _build_input_node(self): ) if t1w_to_mni_errors: raise ClinicaCAPSError( - _format_errors(t1w_to_mni_errors, T1W_TO_MNI_TRANSFORM) + format_clinica_file_reader_errors( + t1w_to_mni_errors, T1W_TO_MNI_TRANSFORM + ) ) if len(self.subjects): diff --git a/clinica/pipelines/pet/volume/pipeline.py b/clinica/pipelines/pet/volume/pipeline.py index b64e5645a..76e7d7bbe 100644 --- a/clinica/pipelines/pet/volume/pipeline.py +++ b/clinica/pipelines/pet/volume/pipeline.py @@ -98,10 +98,10 @@ def _build_input_node(self): t1_volume_native_tpm_in_mni, ) from clinica.utils.inputs import ( - _format_errors, clinica_file_reader, clinica_group_reader, clinica_list_of_files_reader, + format_clinica_file_reader_errors, ) from clinica.utils.stream import cprint from clinica.utils.ux import ( @@ -174,7 +174,7 @@ def _build_input_node(self): ) if flowfields_errors: all_errors.append( - _format_errors( + format_clinica_file_reader_errors( flowfields_errors, t1_volume_deformation_to_template(self.parameters["group_label"]), ) diff --git a/clinica/pipelines/pet_surface/pet_surface_pipeline.py b/clinica/pipelines/pet_surface/pet_surface_pipeline.py index 38b2b598f..54046a037 100644 --- a/clinica/pipelines/pet_surface/pet_surface_pipeline.py +++ b/clinica/pipelines/pet_surface/pet_surface_pipeline.py @@ -78,9 +78,9 @@ def _build_input_node_longitudinal(self): ) from clinica.utils.exceptions import ClinicaException from clinica.utils.inputs import ( - _format_errors, clinica_file_reader, clinica_list_of_files_reader, + format_clinica_file_reader_errors, ) read_parameters_node = npe.Node( @@ -100,7 +100,7 @@ def _build_input_node_longitudinal(self): self._get_pet_scans_query(), ) if pet_errors: - all_errors.append(_format_errors(pet_errors)) + all_errors.append(format_clinica_file_reader_errors(pet_errors)) try: ( @@ -170,9 +170,9 @@ def _build_input_node_cross_sectional(self): ) from clinica.utils.exceptions import ClinicaException from clinica.utils.inputs import ( - _format_errors, clinica_file_reader, clinica_list_of_files_reader, + format_clinica_file_reader_errors, ) read_parameters_node = npe.Node( @@ -191,7 +191,7 @@ def _build_input_node_cross_sectional(self): self._get_pet_scans_query(), ) if pet_errors: - all_errors.append(_format_errors(pet_errors)) + all_errors.append(format_clinica_file_reader_errors(pet_errors)) try: ( diff --git a/clinica/pipelines/t1_volume_dartel2mni/t1_volume_dartel2mni_pipeline.py b/clinica/pipelines/t1_volume_dartel2mni/t1_volume_dartel2mni_pipeline.py index 393349d85..f01b1ac16 100644 --- a/clinica/pipelines/t1_volume_dartel2mni/t1_volume_dartel2mni_pipeline.py +++ b/clinica/pipelines/t1_volume_dartel2mni/t1_volume_dartel2mni_pipeline.py @@ -58,10 +58,10 @@ def _build_input_node(self): t1_volume_native_tpm, ) from clinica.utils.inputs import ( - _format_errors, clinica_file_reader, clinica_group_reader, clinica_list_of_files_reader, + format_clinica_file_reader_errors, ) from clinica.utils.stream import cprint from clinica.utils.ux import ( @@ -117,7 +117,7 @@ def _build_input_node(self): t1_volume_deformation_to_template(self.parameters["group_label"]), ) if flowfield_errors: - all_errors.append(_format_errors(flowfield_errors)) + all_errors.append(format_clinica_file_reader_errors(flowfield_errors)) # Dartel Template # ================ diff --git a/clinica/utils/inputs.py b/clinica/utils/inputs.py index 608e61d62..47a75c0dd 100644 --- a/clinica/utils/inputs.py +++ b/clinica/utils/inputs.py @@ -271,18 +271,17 @@ def check_caps_folder(caps_directory: Union[str, os.PathLike]) -> None: raise ClinicaCAPSError(error_string) -def find_sub_ses_pattern_path( +def find_images_path( input_directory: os.PathLike, subject: str, session: str, - error_encountered: list, - results: list, + errors: List[InvalidSubjectSession], + valid_paths: List[str], is_bids: bool, pattern: str, ) -> None: - """Appends the output path corresponding to subject, session and pattern in results. - - If an error is encountered, its (subject,session) couple is added to the list `errors_encountered`. + """Appends the resulting path corresponding to subject, session and pattern in valid_paths. + If an error is encountered, its (subject,session) couple is added to the list `errors`. Parameters ---------- @@ -301,10 +300,10 @@ def find_sub_ses_pattern_path( session : str Name given to the folder of a session (ex: ses-M00). - error_encountered : List + errors : List List to which errors encountered in this function are added. - results : List + valid_paths : List List to which the output path corresponding to subject, session and pattern is added. @@ -344,14 +343,14 @@ def find_sub_ses_pattern_path( f"Clinica will proceed with the latest run available, that is \n\n-{selected}.", lvl="warning", ) - results.append(selected) + valid_paths.append(selected) else: - error_encountered += [InvalidSubjectSession(subject, session)] + errors.append(InvalidSubjectSession(subject, session)) elif len(current_glob_found) == 0: - error_encountered += [InvalidSubjectSession(subject, session)] + errors.append(InvalidSubjectSession(subject, session)) # Otherwise the file found is added to the result else: - results.append(current_glob_found[0]) + valid_paths.append(current_glob_found[0]) def _are_multiple_runs(files: List[str]) -> bool: @@ -572,21 +571,23 @@ def clinica_file_filter( sessions: List[str], input_directory: Path, information: Dict, - n_procs: Optional[int] = 1, + n_procs: int = 1, ) -> Tuple[List[str], List[str], List[str]]: from clinica.utils.stream import cprint files, errors = clinica_file_reader( subjects, sessions, input_directory, information, n_procs ) - cprint(_format_errors(errors, information), "warning") + cprint(format_clinica_file_reader_errors(errors, information), "warning") filtered_subjects, filtered_sessions = _remove_sub_ses_from_list( subjects, sessions, errors ) return files, filtered_subjects, filtered_sessions -def _format_errors(errors: Iterable[InvalidSubjectSession], information: Dict) -> str: +def format_clinica_file_reader_errors( + errors: Iterable[InvalidSubjectSession], information: Dict +) -> str: message = ( f"Clinica encountered {len(errors)} " f"problem(s) while getting {information['description']}:\n" @@ -606,34 +607,34 @@ def _format_errors(errors: Iterable[InvalidSubjectSession], information: Dict) - def _remove_sub_ses_from_list( - list_subjects: List[str], - list_sessions: List[str], - wrong_sub_ses: Iterable[InvalidSubjectSession], + subjects: List[str], + sessions: List[str], + errors: Iterable[InvalidSubjectSession], ) -> Tuple[List[str], List[str]]: - list_subjects = list_subjects.copy() - list_sessions = list_sessions.copy() - for invalid in wrong_sub_ses: + subjects = subjects.copy() + sessions = sessions.copy() + for invalid in errors: sub_indexes = [ - i for i, subject in enumerate(list_subjects) if subject == invalid.subject + i for i, subject in enumerate(subjects) if subject == invalid.subject ] session_indexes = [ - i for i, session in enumerate(list_sessions) if session == invalid.session + i for i, session in enumerate(sessions) if session == invalid.session ] to_remove = list(set(sub_indexes) & set(session_indexes)) to_remove.sort(reverse=True) for index in to_remove: - list_subjects.pop(index) - list_sessions.pop(index) - return list_subjects, list_sessions + subjects.pop(index) + sessions.pop(index) + return subjects, sessions # todo : generalize def clinica_file_reader( - subjects: List[str], - sessions: List[str], + subjects: Iterable[str], + sessions: Iterable[str], input_directory: os.PathLike, information: Dict, - n_procs: Optional[int] = 1, + n_procs: int = 1, ) -> Tuple[List[str], List[InvalidSubjectSession]]: """Read files in BIDS or CAPS directory based on participant ID(s). @@ -778,8 +779,8 @@ def clinica_file_reader( def _read_files_parallel( input_directory: os.PathLike, - subjects: List[str], - sessions: List[str], + subjects: Iterable[str], + sessions: Iterable[str], is_bids: bool, pattern: str, n_procs: int, @@ -792,7 +793,7 @@ def _read_files_parallel( shared_results = manager.list() shared_errors_encountered = manager.list() Parallel(n_jobs=n_procs)( - delayed(find_sub_ses_pattern_path)( + delayed(find_images_path)( input_directory, sub, ses, @@ -804,23 +805,21 @@ def _read_files_parallel( for sub, ses in zip(subjects, sessions) ) results = list(shared_results) - errors_encountered = list( - shared_errors_encountered - ) # todo : "list" needed ? to test + errors_encountered = list(shared_errors_encountered) return results, errors_encountered def _read_files_sequential( input_directory: os.PathLike, - subjects: List[str], - sessions: List[str], + subjects: Iterable[str], + sessions: Iterable[str], is_bids: bool, pattern: str, **kwargs, ) -> Tuple[List[str], List[InvalidSubjectSession]]: errors_encountered, results = [], [] for sub, ses in zip(subjects, sessions): - find_sub_ses_pattern_path( + find_images_path( input_directory, sub, ses, errors_encountered, results, is_bids, pattern ) return results, errors_encountered @@ -879,7 +878,7 @@ def clinica_list_of_files_reader( if any(all_errors) and raise_exception: error_message = "Clinica faced error(s) while trying to read files in your BIDS or CAPS directory.\n" for error, info in zip(all_errors, list_information): - error_message += _format_errors(error, info) + error_message += format_clinica_file_reader_errors(error, info) raise ClinicaBIDSError(error_message) return list_found_files diff --git a/test/unittests/utils/test_utils_inputs.py b/test/unittests/utils/test_utils_inputs.py index 5fe10a1f2..265ca48da 100644 --- a/test/unittests/utils/test_utils_inputs.py +++ b/test/unittests/utils/test_utils_inputs.py @@ -411,14 +411,14 @@ def test_check_caps_folder(tmp_path): check_caps_folder(tmp_path) -def test_find_sub_ses_pattern_path_error_no_file(tmp_path): - """Test function `find_sub_ses_pattern_path`.""" - from clinica.utils.inputs import find_sub_ses_pattern_path +def test_find_images_path_error_no_file(tmp_path): + """Test function `find_images_path`.""" + from clinica.utils.inputs import find_images_path (tmp_path / "sub-01" / "ses-M00" / "anat").mkdir(parents=True) errors, results = [], [] - find_sub_ses_pattern_path( + find_images_path( tmp_path, "sub-01", "ses-M00", errors, results, True, "sub-*_ses-*_t1w.nii*" ) @@ -427,9 +427,9 @@ def test_find_sub_ses_pattern_path_error_no_file(tmp_path): assert errors[0] == ("sub-01", "ses-M00") -def test_find_sub_ses_pattern_path_error_more_than_one_file(tmp_path): - """Test function `find_sub_ses_pattern_path`.""" - from clinica.utils.inputs import find_sub_ses_pattern_path +def test_find_images_path_error_more_than_one_file(tmp_path): + """Test function `find_images_path`.""" + from clinica.utils.inputs import find_images_path errors, results = [], [] (tmp_path / "sub-01" / "ses-M00" / "anat" / "sub-01_ses-M00_T1w.nii.gz").mkdir( @@ -439,7 +439,7 @@ def test_find_sub_ses_pattern_path_error_more_than_one_file(tmp_path): tmp_path / "sub-01" / "ses-M00" / "anat" / "sub-01_ses-M00_foo-bar_T1w.nii.gz" ).mkdir(parents=True) - find_sub_ses_pattern_path( + find_images_path( tmp_path, "sub-01", "ses-M00", errors, results, True, "sub-*_ses-*_t1w.nii*" ) @@ -448,16 +448,16 @@ def test_find_sub_ses_pattern_path_error_more_than_one_file(tmp_path): assert errors[0] == ("sub-01", "ses-M00") -def test_find_sub_ses_pattern_path(tmp_path): - """Test function `find_sub_ses_pattern_path`.""" - from clinica.utils.inputs import find_sub_ses_pattern_path +def test_find_images_path(tmp_path): + """Test function `find_images_path`.""" + from clinica.utils.inputs import find_images_path (tmp_path / "sub-01" / "ses-M00" / "anat" / "sub-01_ses-M00_T1w.nii.gz").mkdir( parents=True ) errors, results = [], [] - find_sub_ses_pattern_path( + find_images_path( tmp_path, "sub-01", "ses-M00", errors, results, True, "sub-*_ses-*_t1w.nii*" ) @@ -468,8 +468,8 @@ def test_find_sub_ses_pattern_path(tmp_path): ) -def test_find_sub_ses_pattern_path_multiple_runs(tmp_path): - from clinica.utils.inputs import find_sub_ses_pattern_path +def test_find_images_path_multiple_runs(tmp_path): + from clinica.utils.inputs import find_images_path errors, results = [], [] ( @@ -487,7 +487,7 @@ def test_find_sub_ses_pattern_path_multiple_runs(tmp_path): / "sub-01_ses-M06_run-02_foo-bar_T1w.nii.gz" ).mkdir(parents=True) - find_sub_ses_pattern_path( + find_images_path( tmp_path, "sub-01", "ses-M06", errors, results, True, "sub-*_ses-*_t1w.nii*" ) @@ -529,15 +529,15 @@ def test_check_information(): def test_format_errors(): """Test utility function `_format_errors`.""" - from clinica.utils.inputs import _format_errors + from clinica.utils.inputs import format_clinica_file_reader_errors information = {"description": "foo bar baz"} assert ( - _format_errors([], information) + format_clinica_file_reader_errors([], information) == "Clinica encountered 0 problem(s) while getting foo bar baz:\n" ) information["needed_pipeline"] = ["pipeline_1", "pipeline_3"] - assert _format_errors([], information) == ( + assert format_clinica_file_reader_errors([], information) == ( "Clinica encountered 0 problem(s) while getting foo bar baz:\n" "Please note that the following clinica pipeline(s) must have " "run to obtain these files: ['pipeline_1', 'pipeline_3']\n" @@ -547,7 +547,7 @@ def test_format_errors(): InvalidSubjectSession("sub2", "ses1"), InvalidSubjectSession("sub3", "ses1"), ] - assert _format_errors(errors, information) == ( + assert format_clinica_file_reader_errors(errors, information) == ( "Clinica encountered 3 problem(s) while getting foo bar baz:\n" "Please note that the following clinica pipeline(s) must have " "run to obtain these files: ['pipeline_1', 'pipeline_3']\n" @@ -555,7 +555,7 @@ def test_format_errors(): "Clinica could not identify which file to use (missing or too many) for these sessions. They will not be processed." ) information.pop("needed_pipeline") - assert _format_errors(errors, information) == ( + assert format_clinica_file_reader_errors(errors, information) == ( "Clinica encountered 3 problem(s) while getting foo bar baz:\n" "\t* (sub1 | ses1)\n\t* (sub2 | ses1)\n\t* (sub3 | ses1)\n" "Clinica could not identify which file to use (missing or too many) for these sessions. They will not be processed."