junifer 0.0.5__py3-none-any.whl → 0.0.5.dev24__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (194) hide show
  1. junifer/__init__.py +0 -17
  2. junifer/_version.py +2 -2
  3. junifer/api/__init__.py +1 -4
  4. junifer/api/cli.py +1 -91
  5. junifer/api/decorators.py +0 -9
  6. junifer/api/functions.py +10 -56
  7. junifer/api/parser.py +0 -3
  8. junifer/api/queue_context/__init__.py +1 -4
  9. junifer/api/res/afni/run_afni_docker.sh +1 -1
  10. junifer/api/res/ants/run_ants_docker.sh +1 -1
  11. junifer/api/res/fsl/run_fsl_docker.sh +1 -1
  12. junifer/api/tests/test_api_utils.py +2 -4
  13. junifer/api/tests/test_cli.py +0 -83
  14. junifer/api/tests/test_functions.py +2 -27
  15. junifer/configs/__init__.py +1 -1
  16. junifer/configs/juseless/__init__.py +1 -4
  17. junifer/configs/juseless/datagrabbers/__init__.py +1 -10
  18. junifer/configs/juseless/datagrabbers/aomic_id1000_vbm.py +0 -3
  19. junifer/configs/juseless/datagrabbers/camcan_vbm.py +0 -3
  20. junifer/configs/juseless/datagrabbers/ixi_vbm.py +0 -3
  21. junifer/configs/juseless/datagrabbers/tests/test_ucla.py +3 -1
  22. junifer/configs/juseless/datagrabbers/ucla.py +9 -12
  23. junifer/configs/juseless/datagrabbers/ukb_vbm.py +0 -3
  24. junifer/data/__init__.py +1 -21
  25. junifer/data/coordinates.py +19 -10
  26. junifer/data/masks.py +87 -58
  27. junifer/data/parcellations.py +3 -14
  28. junifer/data/template_spaces.py +1 -4
  29. junifer/data/tests/test_masks.py +37 -26
  30. junifer/data/utils.py +0 -3
  31. junifer/datagrabber/__init__.py +1 -18
  32. junifer/datagrabber/aomic/__init__.py +0 -3
  33. junifer/datagrabber/aomic/id1000.py +37 -70
  34. junifer/datagrabber/aomic/piop1.py +36 -69
  35. junifer/datagrabber/aomic/piop2.py +38 -71
  36. junifer/datagrabber/aomic/tests/test_id1000.py +99 -44
  37. junifer/datagrabber/aomic/tests/test_piop1.py +108 -65
  38. junifer/datagrabber/aomic/tests/test_piop2.py +102 -45
  39. junifer/datagrabber/base.py +6 -13
  40. junifer/datagrabber/datalad_base.py +1 -13
  41. junifer/datagrabber/dmcc13_benchmark.py +53 -36
  42. junifer/datagrabber/hcp1200/__init__.py +0 -3
  43. junifer/datagrabber/hcp1200/datalad_hcp1200.py +0 -3
  44. junifer/datagrabber/hcp1200/hcp1200.py +1 -4
  45. junifer/datagrabber/multiple.py +6 -45
  46. junifer/datagrabber/pattern.py +62 -170
  47. junifer/datagrabber/pattern_datalad.py +12 -25
  48. junifer/datagrabber/tests/test_datagrabber_utils.py +218 -0
  49. junifer/datagrabber/tests/test_datalad_base.py +4 -4
  50. junifer/datagrabber/tests/test_dmcc13_benchmark.py +19 -46
  51. junifer/datagrabber/tests/test_multiple.py +84 -161
  52. junifer/datagrabber/tests/test_pattern.py +0 -45
  53. junifer/datagrabber/tests/test_pattern_datalad.py +4 -4
  54. junifer/datagrabber/utils.py +230 -0
  55. junifer/datareader/__init__.py +1 -4
  56. junifer/datareader/default.py +43 -95
  57. junifer/external/__init__.py +1 -1
  58. junifer/external/nilearn/__init__.py +1 -5
  59. junifer/external/nilearn/junifer_nifti_spheres_masker.py +9 -23
  60. junifer/external/nilearn/tests/test_junifer_nifti_spheres_masker.py +1 -76
  61. junifer/markers/__init__.py +1 -23
  62. junifer/markers/base.py +28 -68
  63. junifer/markers/collection.py +2 -10
  64. junifer/markers/complexity/__init__.py +0 -10
  65. junifer/markers/complexity/complexity_base.py +43 -26
  66. junifer/markers/complexity/hurst_exponent.py +0 -3
  67. junifer/markers/complexity/multiscale_entropy_auc.py +0 -3
  68. junifer/markers/complexity/perm_entropy.py +0 -3
  69. junifer/markers/complexity/range_entropy.py +0 -3
  70. junifer/markers/complexity/range_entropy_auc.py +0 -3
  71. junifer/markers/complexity/sample_entropy.py +0 -3
  72. junifer/markers/complexity/tests/test_hurst_exponent.py +3 -11
  73. junifer/markers/complexity/tests/test_multiscale_entropy_auc.py +3 -11
  74. junifer/markers/complexity/tests/test_perm_entropy.py +3 -11
  75. junifer/markers/complexity/tests/test_range_entropy.py +3 -11
  76. junifer/markers/complexity/tests/test_range_entropy_auc.py +3 -11
  77. junifer/markers/complexity/tests/test_sample_entropy.py +3 -11
  78. junifer/markers/complexity/tests/test_weighted_perm_entropy.py +3 -11
  79. junifer/markers/complexity/weighted_perm_entropy.py +0 -3
  80. junifer/markers/ets_rss.py +42 -27
  81. junifer/markers/falff/__init__.py +0 -3
  82. junifer/markers/falff/_afni_falff.py +2 -5
  83. junifer/markers/falff/_junifer_falff.py +0 -3
  84. junifer/markers/falff/falff_base.py +46 -20
  85. junifer/markers/falff/falff_parcels.py +27 -56
  86. junifer/markers/falff/falff_spheres.py +29 -60
  87. junifer/markers/falff/tests/test_falff_parcels.py +23 -39
  88. junifer/markers/falff/tests/test_falff_spheres.py +23 -39
  89. junifer/markers/functional_connectivity/__init__.py +0 -9
  90. junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +60 -63
  91. junifer/markers/functional_connectivity/edge_functional_connectivity_parcels.py +32 -45
  92. junifer/markers/functional_connectivity/edge_functional_connectivity_spheres.py +36 -49
  93. junifer/markers/functional_connectivity/functional_connectivity_base.py +70 -71
  94. junifer/markers/functional_connectivity/functional_connectivity_parcels.py +25 -34
  95. junifer/markers/functional_connectivity/functional_connectivity_spheres.py +30 -40
  96. junifer/markers/functional_connectivity/tests/test_crossparcellation_functional_connectivity.py +7 -11
  97. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_parcels.py +7 -27
  98. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_spheres.py +12 -28
  99. junifer/markers/functional_connectivity/tests/test_functional_connectivity_parcels.py +11 -35
  100. junifer/markers/functional_connectivity/tests/test_functional_connectivity_spheres.py +62 -36
  101. junifer/markers/parcel_aggregation.py +61 -47
  102. junifer/markers/reho/__init__.py +0 -3
  103. junifer/markers/reho/_afni_reho.py +2 -5
  104. junifer/markers/reho/_junifer_reho.py +1 -4
  105. junifer/markers/reho/reho_base.py +27 -8
  106. junifer/markers/reho/reho_parcels.py +17 -28
  107. junifer/markers/reho/reho_spheres.py +18 -27
  108. junifer/markers/reho/tests/test_reho_parcels.py +3 -8
  109. junifer/markers/reho/tests/test_reho_spheres.py +3 -8
  110. junifer/markers/sphere_aggregation.py +59 -43
  111. junifer/markers/temporal_snr/__init__.py +0 -3
  112. junifer/markers/temporal_snr/temporal_snr_base.py +32 -23
  113. junifer/markers/temporal_snr/temporal_snr_parcels.py +6 -9
  114. junifer/markers/temporal_snr/temporal_snr_spheres.py +6 -9
  115. junifer/markers/temporal_snr/tests/test_temporal_snr_parcels.py +3 -6
  116. junifer/markers/temporal_snr/tests/test_temporal_snr_spheres.py +3 -6
  117. junifer/markers/tests/test_collection.py +8 -9
  118. junifer/markers/tests/test_ets_rss.py +9 -15
  119. junifer/markers/tests/test_markers_base.py +18 -17
  120. junifer/markers/tests/test_parcel_aggregation.py +32 -93
  121. junifer/markers/tests/test_sphere_aggregation.py +19 -72
  122. junifer/onthefly/__init__.py +1 -4
  123. junifer/onthefly/read_transform.py +0 -3
  124. junifer/pipeline/__init__.py +1 -9
  125. junifer/pipeline/pipeline_step_mixin.py +4 -21
  126. junifer/pipeline/registry.py +0 -3
  127. junifer/pipeline/singleton.py +0 -3
  128. junifer/pipeline/tests/test_registry.py +1 -1
  129. junifer/pipeline/update_meta_mixin.py +0 -3
  130. junifer/pipeline/utils.py +1 -67
  131. junifer/pipeline/workdir_manager.py +0 -3
  132. junifer/preprocess/__init__.py +2 -9
  133. junifer/preprocess/ants/__init__.py +4 -0
  134. junifer/preprocess/ants/ants_apply_transforms_warper.py +185 -0
  135. junifer/preprocess/ants/tests/test_ants_apply_transforms_warper.py +56 -0
  136. junifer/preprocess/base.py +3 -6
  137. junifer/preprocess/bold_warper.py +265 -0
  138. junifer/preprocess/confounds/__init__.py +0 -3
  139. junifer/preprocess/confounds/fmriprep_confound_remover.py +60 -47
  140. junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py +113 -72
  141. junifer/preprocess/fsl/__init__.py +4 -0
  142. junifer/preprocess/fsl/apply_warper.py +179 -0
  143. junifer/preprocess/fsl/tests/test_apply_warper.py +45 -0
  144. junifer/preprocess/smoothing/__init__.py +0 -3
  145. junifer/preprocess/smoothing/_afni_smoothing.py +1 -1
  146. junifer/preprocess/tests/test_bold_warper.py +159 -0
  147. junifer/preprocess/warping/__init__.py +0 -3
  148. junifer/preprocess/warping/_ants_warper.py +0 -3
  149. junifer/preprocess/warping/_fsl_warper.py +0 -3
  150. junifer/stats.py +1 -4
  151. junifer/storage/__init__.py +1 -9
  152. junifer/storage/base.py +1 -40
  153. junifer/storage/hdf5.py +9 -71
  154. junifer/storage/pandas_base.py +0 -3
  155. junifer/storage/sqlite.py +0 -3
  156. junifer/storage/tests/test_hdf5.py +10 -82
  157. junifer/storage/utils.py +0 -9
  158. junifer/testing/__init__.py +1 -4
  159. junifer/testing/datagrabbers.py +6 -13
  160. junifer/testing/tests/test_partlycloudytesting_datagrabber.py +7 -7
  161. junifer/testing/utils.py +0 -3
  162. junifer/utils/__init__.py +2 -13
  163. junifer/utils/fs.py +0 -3
  164. junifer/utils/helpers.py +1 -32
  165. junifer/utils/logging.py +4 -33
  166. junifer/utils/tests/test_logging.py +0 -8
  167. {junifer-0.0.5.dist-info → junifer-0.0.5.dev24.dist-info}/METADATA +16 -17
  168. junifer-0.0.5.dev24.dist-info/RECORD +265 -0
  169. {junifer-0.0.5.dist-info → junifer-0.0.5.dev24.dist-info}/WHEEL +1 -1
  170. junifer/api/res/freesurfer/mri_binarize +0 -3
  171. junifer/api/res/freesurfer/mri_mc +0 -3
  172. junifer/api/res/freesurfer/mri_pretess +0 -3
  173. junifer/api/res/freesurfer/mris_convert +0 -3
  174. junifer/api/res/freesurfer/run_freesurfer_docker.sh +0 -61
  175. junifer/data/masks/ukb/UKB_15K_GM_template.nii.gz +0 -0
  176. junifer/datagrabber/pattern_validation_mixin.py +0 -388
  177. junifer/datagrabber/tests/test_pattern_validation_mixin.py +0 -249
  178. junifer/external/BrainPrint/brainprint/__init__.py +0 -4
  179. junifer/external/BrainPrint/brainprint/_version.py +0 -3
  180. junifer/external/BrainPrint/brainprint/asymmetry.py +0 -91
  181. junifer/external/BrainPrint/brainprint/brainprint.py +0 -441
  182. junifer/external/BrainPrint/brainprint/surfaces.py +0 -258
  183. junifer/external/BrainPrint/brainprint/utils/__init__.py +0 -1
  184. junifer/external/BrainPrint/brainprint/utils/_config.py +0 -112
  185. junifer/external/BrainPrint/brainprint/utils/utils.py +0 -188
  186. junifer/external/nilearn/junifer_connectivity_measure.py +0 -483
  187. junifer/external/nilearn/tests/test_junifer_connectivity_measure.py +0 -1089
  188. junifer/markers/brainprint.py +0 -459
  189. junifer/markers/tests/test_brainprint.py +0 -58
  190. junifer-0.0.5.dist-info/RECORD +0 -275
  191. {junifer-0.0.5.dist-info → junifer-0.0.5.dev24.dist-info}/AUTHORS.rst +0 -0
  192. {junifer-0.0.5.dist-info → junifer-0.0.5.dev24.dist-info}/LICENSE.md +0 -0
  193. {junifer-0.0.5.dist-info → junifer-0.0.5.dev24.dist-info}/entry_points.txt +0 -0
  194. {junifer-0.0.5.dist-info → junifer-0.0.5.dev24.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,218 @@
1
+ """Provide tests for utils."""
2
+
3
+ # Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
4
+ # License: AGPL
5
+
6
+ from contextlib import nullcontext
7
+ from typing import ContextManager, Dict, List, Union
8
+
9
+ import pytest
10
+
11
+ from junifer.datagrabber.utils import (
12
+ validate_patterns,
13
+ validate_replacements,
14
+ validate_types,
15
+ )
16
+
17
+
18
+ @pytest.mark.parametrize(
19
+ "types, expect",
20
+ [
21
+ ("wrong", pytest.raises(TypeError, match="must be a list")),
22
+ ([1], pytest.raises(TypeError, match="must be a list of strings")),
23
+ (["T1w", "BOLD"], nullcontext()),
24
+ ],
25
+ )
26
+ def test_validate_types(
27
+ types: Union[str, List[str], List[int]],
28
+ expect: ContextManager,
29
+ ) -> None:
30
+ """Test validation of types.
31
+
32
+ Parameters
33
+ ----------
34
+ types : str, list of int or str
35
+ The parametrized data types to validate.
36
+ expect : typing.ContextManager
37
+ The parametrized ContextManager object.
38
+
39
+ """
40
+ with expect:
41
+ validate_types(types) # type: ignore
42
+
43
+
44
+ @pytest.mark.parametrize(
45
+ "replacements, patterns, expect",
46
+ [
47
+ (
48
+ "wrong",
49
+ "also wrong",
50
+ pytest.raises(TypeError, match="must be a list"),
51
+ ),
52
+ (
53
+ [1],
54
+ {
55
+ "T1w": {"pattern": "{subject}/anat/{subject}_T1w.nii.gz"},
56
+ "BOLD": {
57
+ "pattern": "{subject}/func/{subject}_task-rest_bold.nii.gz"
58
+ },
59
+ },
60
+ pytest.raises(TypeError, match="must be a list of strings"),
61
+ ),
62
+ (
63
+ ["session"],
64
+ {
65
+ "T1w": {"pattern": "{subject}/anat/{subject}_T1w.nii.gz"},
66
+ "BOLD": {
67
+ "pattern": "{subject}/func/{subject}_task-rest_bold.nii.gz"
68
+ },
69
+ },
70
+ pytest.raises(ValueError, match="is not part of"),
71
+ ),
72
+ (
73
+ ["subject", "session"],
74
+ {
75
+ "T1w": {"pattern": "{subject}/anat/_T1w.nii.gz"},
76
+ "BOLD": {"pattern": "{session}/func/_task-rest_bold.nii.gz"},
77
+ },
78
+ pytest.raises(ValueError, match="At least one pattern"),
79
+ ),
80
+ (
81
+ ["subject"],
82
+ {
83
+ "T1w": {"pattern": "{subject}/anat/{subject}_T1w.nii.gz"},
84
+ "BOLD": {
85
+ "pattern": "{subject}/func/{subject}_task-rest_bold.nii.gz"
86
+ },
87
+ },
88
+ nullcontext(),
89
+ ),
90
+ ],
91
+ )
92
+ def test_validate_replacements(
93
+ replacements: Union[str, List[str], List[int]],
94
+ patterns: Union[str, Dict[str, Dict[str, str]]],
95
+ expect: ContextManager,
96
+ ) -> None:
97
+ """Test validation of replacements.
98
+
99
+ Parameters
100
+ ----------
101
+ replacements : str, list of str or int
102
+ The parametrized pattern replacements to validate.
103
+ patterns : str, dict
104
+ The parametrized patterns to validate against.
105
+ expect : typing.ContextManager
106
+ The parametrized ContextManager object.
107
+
108
+ """
109
+ with expect:
110
+ validate_replacements(replacements=replacements, patterns=patterns) # type: ignore
111
+
112
+
113
+ @pytest.mark.parametrize(
114
+ "types, patterns, expect",
115
+ [
116
+ (
117
+ ["T1w", "BOLD"],
118
+ "wrong",
119
+ pytest.raises(TypeError, match="must be a dict"),
120
+ ),
121
+ (
122
+ ["T1w", "BOLD"],
123
+ {
124
+ "T1w": {"pattern": "{subject}/anat/{subject}_T1w.nii.gz"},
125
+ },
126
+ pytest.raises(
127
+ ValueError,
128
+ match="Length of `types` more than that of `patterns`.",
129
+ ),
130
+ ),
131
+ (
132
+ ["T1w", "BOLD"],
133
+ {
134
+ "T1w": {"pattern": "{subject}/anat/{subject}_T1w.nii.gz"},
135
+ "T2w": {"pattern": "{subject}/anat/{subject}_T2w.nii.gz"},
136
+ },
137
+ pytest.raises(ValueError, match="contain all"),
138
+ ),
139
+ (
140
+ ["T3w"],
141
+ {
142
+ "T3w": {"pattern": "{subject}/anat/{subject}_T3w.nii.gz"},
143
+ },
144
+ pytest.raises(ValueError, match="Unknown data type"),
145
+ ),
146
+ (
147
+ ["BOLD"],
148
+ {
149
+ "BOLD": {"patterns": "{subject}/func/{subject}_BOLD.nii.gz"},
150
+ },
151
+ pytest.raises(KeyError, match="Mandatory key"),
152
+ ),
153
+ (
154
+ ["BOLD_confounds"],
155
+ {
156
+ "BOLD_confounds": {
157
+ "pattern": "{subject}/func/{subject}_confounds.tsv",
158
+ "format": "fmriprep",
159
+ "space": "MNINLin6Asym",
160
+ },
161
+ },
162
+ pytest.raises(RuntimeError, match="not accepted"),
163
+ ),
164
+ (
165
+ ["T1w"],
166
+ {
167
+ "T1w": {
168
+ "pattern": "{subject}/anat/{subject}*.nii",
169
+ "space": "native",
170
+ },
171
+ },
172
+ pytest.raises(ValueError, match="following a replacement"),
173
+ ),
174
+ (
175
+ ["T1w", "T2w", "BOLD", "BOLD_confounds"],
176
+ {
177
+ "T1w": {
178
+ "pattern": "{subject}/anat/{subject}_T1w.nii.gz",
179
+ "space": "native",
180
+ },
181
+ "T2w": {
182
+ "pattern": "{subject}/anat/{subject}_T2w.nii.gz",
183
+ "space": "native",
184
+ },
185
+ "BOLD": {
186
+ "pattern": (
187
+ "{subject}/func/{subject}_task-rest_bold.nii.gz"
188
+ ),
189
+ "space": "MNI152NLin6Asym",
190
+ },
191
+ "BOLD_confounds": {
192
+ "pattern": "{subject}/func/{subject}_confounds.tsv",
193
+ "format": "fmriprep",
194
+ },
195
+ },
196
+ nullcontext(),
197
+ ),
198
+ ],
199
+ )
200
+ def test_validate_patterns(
201
+ types: List[str],
202
+ patterns: Union[str, Dict[str, Dict[str, str]]],
203
+ expect: ContextManager,
204
+ ) -> None:
205
+ """Test validation of patterns.
206
+
207
+ Parameters
208
+ ----------
209
+ types : list of str
210
+ The parametrized data types.
211
+ patterns : str, dict
212
+ The patterns to validate.
213
+ expect : typing.ContextManager
214
+ The parametrized ContextManager object.
215
+
216
+ """
217
+ with expect:
218
+ validate_patterns(types=types, patterns=patterns) # type: ignore
@@ -15,13 +15,13 @@ from junifer.datagrabber import DataladDataGrabber
15
15
  _testing_dataset = {
16
16
  "example_bids": {
17
17
  "uri": "https://gin.g-node.org/juaml/datalad-example-bids",
18
- "commit": "b87897cbe51bf0ee5514becaa5c7dd76491db5ad",
19
- "id": "8fddff30-6993-420a-9d1e-b5b028c59468",
18
+ "commit": "522dfb203afcd2cd55799bf347f9b211919a7338",
19
+ "id": "fec92475-d9c0-4409-92ba-f041b6a12c40",
20
20
  },
21
21
  "example_bids_ses": {
22
22
  "uri": "https://gin.g-node.org/juaml/datalad-example-bids-ses",
23
- "commit": "6b163aa98af76a9eac0272273c27e14127850181",
24
- "id": "715c17cf-a1b9-42d6-9af8-9f74c1a4a724",
23
+ "commit": "3d08d55d1faad4f12ab64ac9497544a0d924d47a",
24
+ "id": "c83500d0-532f-45be-baf1-0dab703bdc2a",
25
25
  },
26
26
  }
27
27
 
@@ -93,10 +93,13 @@ def test_DMCC13Benchmark(
93
93
  # Available data types
94
94
  data_types = [
95
95
  "BOLD",
96
+ "BOLD_confounds",
97
+ "BOLD_mask",
96
98
  "VBM_CSF",
97
99
  "VBM_GM",
98
100
  "VBM_WM",
99
101
  "T1w",
102
+ "T1w_mask",
100
103
  ]
101
104
  # Add Warp if native T1w is accessed
102
105
  if native_t1w:
@@ -108,6 +111,14 @@ def test_DMCC13Benchmark(
108
111
  f"sub-01_{ses}_task-{task}_acq-mb4{phase}_run-{run}_"
109
112
  "space-MNI152NLin2009cAsym_desc-preproc_bold.nii.gz"
110
113
  ),
114
+ (
115
+ f"sub-01_{ses}_task-{task}_acq-mb4{phase}_run-{run}_"
116
+ "desc-confounds_regressors.tsv"
117
+ ),
118
+ (
119
+ f"sub-01_{ses}_task-{task}_acq-mb4{phase}_run-{run}_"
120
+ "space-MNI152NLin2009cAsym_desc-brain_mask.nii.gz"
121
+ ),
111
122
  "sub-01_space-MNI152NLin2009cAsym_label-CSF_probseg.nii.gz",
112
123
  "sub-01_space-MNI152NLin2009cAsym_label-GM_probseg.nii.gz",
113
124
  "sub-01_space-MNI152NLin2009cAsym_label-WM_probseg.nii.gz",
@@ -116,12 +127,16 @@ def test_DMCC13Benchmark(
116
127
  data_file_names.extend(
117
128
  [
118
129
  "sub-01_desc-preproc_T1w.nii.gz",
130
+ "sub-01_desc-brain_mask.nii.gz",
119
131
  "sub-01_from-MNI152NLin2009cAsym_to-T1w_mode-image_xfm.h5",
120
132
  ]
121
133
  )
122
134
  else:
123
- data_file_names.append(
124
- "sub-01_space-MNI152NLin2009cAsym_desc-preproc_T1w.nii.gz"
135
+ data_file_names.extend(
136
+ [
137
+ "sub-01_space-MNI152NLin2009cAsym_desc-preproc_T1w.nii.gz",
138
+ "sub-01_space-MNI152NLin2009cAsym_desc-brain_mask.nii.gz",
139
+ ]
125
140
  )
126
141
 
127
142
  for data_type, data_file_name in zip(data_types, data_file_names):
@@ -136,48 +151,6 @@ def test_DMCC13Benchmark(
136
151
  # Assert metadata
137
152
  assert "meta" in out[data_type]
138
153
 
139
- # Check BOLD nested data types
140
- for type_, file_name in zip(
141
- ("mask", "confounds"),
142
- (
143
- (
144
- f"sub-01_{ses}_task-{task}_acq-mb4{phase}_run-{run}_"
145
- "space-MNI152NLin2009cAsym_desc-brain_mask.nii.gz"
146
- ),
147
- (
148
- f"sub-01_{ses}_task-{task}_acq-mb4{phase}_run-{run}_"
149
- "desc-confounds_regressors.tsv"
150
- ),
151
- ),
152
- ):
153
- # Assert data type
154
- assert type_ in out["BOLD"]
155
- # Assert data file path exists
156
- assert out["BOLD"][type_]["path"].exists()
157
- # Assert data file path is a file
158
- assert out["BOLD"][type_]["path"].is_file()
159
- # Assert data file name
160
- assert out["BOLD"][type_]["path"].name == file_name
161
-
162
- # Check T1w nested data types
163
- # Assert data type
164
- assert "mask" in out["T1w"]
165
- # Assert data file path exists
166
- assert out["T1w"]["mask"]["path"].exists()
167
- # Assert data file path is a file
168
- assert out["T1w"]["mask"]["path"].is_file()
169
- # Assert data file name
170
- if native_t1w:
171
- assert (
172
- out["T1w"]["mask"]["path"].name
173
- == "sub-01_desc-brain_mask.nii.gz"
174
- )
175
- else:
176
- assert (
177
- out["T1w"]["mask"]["path"].name
178
- == "sub-01_space-MNI152NLin2009cAsym_desc-brain_mask.nii.gz"
179
- )
180
-
181
154
 
182
155
  @pytest.mark.parametrize(
183
156
  "types, native_t1w",
@@ -192,8 +165,8 @@ def test_DMCC13Benchmark(
192
165
  ("VBM_GM", False),
193
166
  ("VBM_WM", True),
194
167
  ("VBM_WM", False),
195
- (["BOLD", "VBM_CSF"], True),
196
- (["BOLD", "VBM_CSF"], False),
168
+ (["BOLD", "BOLD_confounds"], True),
169
+ (["BOLD", "BOLD_confounds"], False),
197
170
  (["T1w", "VBM_CSF"], True),
198
171
  (["T1w", "VBM_CSF"], False),
199
172
  (["VBM_GM", "VBM_WM"], True),
@@ -25,26 +25,28 @@ def test_MultipleDataGrabber() -> None:
25
25
  repo_uri = _testing_dataset["example_bids_ses"]["uri"]
26
26
  rootdir = "example_bids_ses"
27
27
  replacements = ["subject", "session"]
28
-
28
+ pattern1 = {
29
+ "T1w": {
30
+ "pattern": (
31
+ "{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz"
32
+ ),
33
+ "space": "native",
34
+ },
35
+ }
36
+ pattern2 = {
37
+ "BOLD": {
38
+ "pattern": (
39
+ "{subject}/{session}/func/"
40
+ "{subject}_{session}_task-rest_bold.nii.gz"
41
+ ),
42
+ "space": "MNI152NLin6Asym",
43
+ },
44
+ }
29
45
  dg1 = PatternDataladDataGrabber(
30
46
  rootdir=rootdir,
31
47
  uri=repo_uri,
32
48
  types=["T1w"],
33
- patterns={
34
- "T1w": {
35
- "pattern": (
36
- "{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz"
37
- ),
38
- "space": "native",
39
- "mask": {
40
- "pattern": (
41
- "{subject}/{session}/anat/{subject}_{session}_"
42
- "brain_mask.nii.gz"
43
- ),
44
- "space": "native",
45
- },
46
- },
47
- },
49
+ patterns=pattern1,
48
50
  replacements=replacements,
49
51
  )
50
52
 
@@ -52,22 +54,7 @@ def test_MultipleDataGrabber() -> None:
52
54
  rootdir=rootdir,
53
55
  uri=repo_uri,
54
56
  types=["BOLD"],
55
- patterns={
56
- "BOLD": {
57
- "pattern": (
58
- "{subject}/{session}/func/"
59
- "{subject}_{session}_task-rest_bold.nii.gz"
60
- ),
61
- "space": "MNI152NLin6Asym",
62
- "mask": {
63
- "pattern": (
64
- "{subject}/{session}/func/"
65
- "{subject}_{session}_task-rest_brain_mask.nii.gz"
66
- ),
67
- "space": "MNI152NLin6Asym",
68
- },
69
- },
70
- },
57
+ patterns=pattern2,
71
58
  replacements=replacements,
72
59
  )
73
60
 
@@ -86,17 +73,14 @@ def test_MultipleDataGrabber() -> None:
86
73
  with dg:
87
74
  subs = list(dg)
88
75
  assert set(subs) == set(expected_subs)
89
- # Check data type
76
+
90
77
  elem = dg[("sub-01", "ses-01")]
91
- # Check data types
92
78
  assert "T1w" in elem
93
79
  assert "BOLD" in elem
94
- # Check meta
95
80
  assert "meta" in elem["BOLD"]
96
81
  meta = elem["BOLD"]["meta"]["datagrabber"]
97
82
  assert "class" in meta
98
83
  assert meta["class"] == "MultipleDataGrabber"
99
- # Check datagrabbers
100
84
  assert "datagrabbers" in meta
101
85
  assert len(meta["datagrabbers"]) == 2
102
86
  assert meta["datagrabbers"][0]["class"] == "PatternDataladDataGrabber"
@@ -105,37 +89,40 @@ def test_MultipleDataGrabber() -> None:
105
89
 
106
90
  def test_MultipleDataGrabber_no_intersection() -> None:
107
91
  """Test MultipleDataGrabber without intersection (0 elements)."""
92
+ repo_uri1 = _testing_dataset["example_bids"]["uri"]
93
+ repo_uri2 = _testing_dataset["example_bids_ses"]["uri"]
108
94
  rootdir = "example_bids_ses"
109
95
  replacements = ["subject", "session"]
110
-
96
+ pattern1 = {
97
+ "T1w": {
98
+ "pattern": (
99
+ "{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz"
100
+ ),
101
+ "space": "native",
102
+ },
103
+ }
104
+ pattern2 = {
105
+ "BOLD": {
106
+ "pattern": (
107
+ "{subject}/{session}/func/"
108
+ "{subject}_{session}_task-rest_bold.nii.gz"
109
+ ),
110
+ "space": "MNI152NLin6Asym",
111
+ },
112
+ }
111
113
  dg1 = PatternDataladDataGrabber(
112
114
  rootdir=rootdir,
113
- uri=_testing_dataset["example_bids"]["uri"],
115
+ uri=repo_uri1,
114
116
  types=["T1w"],
115
- patterns={
116
- "T1w": {
117
- "pattern": (
118
- "{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz"
119
- ),
120
- "space": "native",
121
- },
122
- },
117
+ patterns=pattern1,
123
118
  replacements=replacements,
124
119
  )
125
120
 
126
121
  dg2 = PatternDataladDataGrabber(
127
122
  rootdir=rootdir,
128
- uri=_testing_dataset["example_bids_ses"]["uri"],
123
+ uri=repo_uri2,
129
124
  types=["BOLD"],
130
- patterns={
131
- "BOLD": {
132
- "pattern": (
133
- "{subject}/{session}/func/"
134
- "{subject}_{session}_task-rest_bold.nii.gz"
135
- ),
136
- "space": "MNI152NLin6Asym",
137
- },
138
- },
125
+ patterns=pattern2,
139
126
  replacements=replacements,
140
127
  )
141
128
 
@@ -148,19 +135,23 @@ def test_MultipleDataGrabber_no_intersection() -> None:
148
135
 
149
136
  def test_MultipleDataGrabber_get_item() -> None:
150
137
  """Test MultipleDataGrabber get_item() error."""
138
+ repo_uri1 = _testing_dataset["example_bids"]["uri"]
139
+ rootdir = "example_bids_ses"
140
+ replacements = ["subject", "session"]
141
+ pattern1 = {
142
+ "T1w": {
143
+ "pattern": (
144
+ "{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz"
145
+ ),
146
+ "space": "native",
147
+ },
148
+ }
151
149
  dg1 = PatternDataladDataGrabber(
152
- rootdir="example_bids_ses",
153
- uri=_testing_dataset["example_bids"]["uri"],
150
+ rootdir=rootdir,
151
+ uri=repo_uri1,
154
152
  types=["T1w"],
155
- patterns={
156
- "T1w": {
157
- "pattern": (
158
- "{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz"
159
- ),
160
- "space": "native",
161
- },
162
- },
163
- replacements=["subject", "session"],
153
+ patterns=pattern1,
154
+ replacements=replacements,
164
155
  )
165
156
 
166
157
  dg = MultipleDataGrabber([dg1])
@@ -170,111 +161,43 @@ def test_MultipleDataGrabber_get_item() -> None:
170
161
 
171
162
  def test_MultipleDataGrabber_validation() -> None:
172
163
  """Test MultipleDataGrabber init validation."""
164
+ repo_uri1 = _testing_dataset["example_bids"]["uri"]
165
+ repo_uri2 = _testing_dataset["example_bids_ses"]["uri"]
173
166
  rootdir = "example_bids_ses"
174
-
167
+ replacement1 = ["subject", "session"]
168
+ replacement2 = ["subject"]
169
+ pattern1 = {
170
+ "T1w": {
171
+ "pattern": (
172
+ "{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz"
173
+ ),
174
+ "space": "native",
175
+ },
176
+ }
177
+ pattern2 = {
178
+ "BOLD": {
179
+ "pattern": "{subject}/func/{subject}_task-rest_bold.nii.gz",
180
+ "space": "MNI152NLin6Asym",
181
+ },
182
+ }
175
183
  dg1 = PatternDataladDataGrabber(
176
184
  rootdir=rootdir,
177
- uri=_testing_dataset["example_bids"]["uri"],
185
+ uri=repo_uri1,
178
186
  types=["T1w"],
179
- patterns={
180
- "T1w": {
181
- "pattern": (
182
- "{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz"
183
- ),
184
- "space": "native",
185
- },
186
- },
187
- replacements=["subject", "session"],
187
+ patterns=pattern1,
188
+ replacements=replacement1,
188
189
  )
189
190
 
190
191
  dg2 = PatternDataladDataGrabber(
191
192
  rootdir=rootdir,
192
- uri=_testing_dataset["example_bids_ses"]["uri"],
193
+ uri=repo_uri2,
193
194
  types=["BOLD"],
194
- patterns={
195
- "BOLD": {
196
- "pattern": "{subject}/func/{subject}_task-rest_bold.nii.gz",
197
- "space": "MNI152NLin6Asym",
198
- },
199
- },
200
- replacements=["subject"],
195
+ patterns=pattern2,
196
+ replacements=replacement2,
201
197
  )
202
198
 
203
- with pytest.raises(RuntimeError, match="have different element keys"):
199
+ with pytest.raises(ValueError, match="different element key"):
204
200
  MultipleDataGrabber([dg1, dg2])
205
201
 
206
- with pytest.raises(RuntimeError, match="have overlapping mandatory"):
202
+ with pytest.raises(ValueError, match="overlapping types"):
207
203
  MultipleDataGrabber([dg1, dg1])
208
-
209
-
210
- def test_MultipleDataGrabber_partial_pattern() -> None:
211
- """Test MultipleDataGrabber partial pattern."""
212
- repo_uri = _testing_dataset["example_bids_ses"]["uri"]
213
- rootdir = "example_bids_ses"
214
- replacements = ["subject", "session"]
215
-
216
- dg1 = PatternDataladDataGrabber(
217
- rootdir=rootdir,
218
- uri=repo_uri,
219
- types=["BOLD"],
220
- patterns={
221
- "BOLD": {
222
- "pattern": (
223
- "{subject}/{session}/func/"
224
- "{subject}_{session}_task-rest_bold.nii.gz"
225
- ),
226
- "space": "MNI152NLin6Asym",
227
- },
228
- },
229
- replacements=replacements,
230
- )
231
-
232
- dg2 = PatternDataladDataGrabber(
233
- rootdir=rootdir,
234
- uri=repo_uri,
235
- types=["BOLD"],
236
- patterns={
237
- "BOLD": {
238
- "confounds": {
239
- "pattern": (
240
- "{subject}/{session}/func/"
241
- "{subject}_{session}_task-rest_"
242
- "confounds_regressors.tsv"
243
- ),
244
- "format": "fmriprep",
245
- },
246
- },
247
- },
248
- replacements=["subject", "session"],
249
- partial_pattern_ok=True,
250
- )
251
-
252
- dg = MultipleDataGrabber([dg1, dg2])
253
-
254
- types = dg.get_types()
255
- assert "BOLD" in types
256
-
257
- expected_subs = [
258
- (f"sub-{i:02d}", f"ses-{j:02d}")
259
- for j in range(1, 3)
260
- for i in range(1, 10)
261
- ]
262
-
263
- with dg:
264
- subs = list(dg)
265
- assert set(subs) == set(expected_subs)
266
- # Fetch element
267
- elem = dg[("sub-01", "ses-01")]
268
- # Check data type and nested data type
269
- assert "BOLD" in elem
270
- assert "confounds" in elem["BOLD"]
271
- # Check meta
272
- assert "meta" in elem["BOLD"]
273
- meta = elem["BOLD"]["meta"]["datagrabber"]
274
- assert "class" in meta
275
- assert meta["class"] == "MultipleDataGrabber"
276
- # Check datagrabbers
277
- assert "datagrabbers" in meta
278
- assert len(meta["datagrabbers"]) == 2
279
- assert meta["datagrabbers"][0]["class"] == "PatternDataladDataGrabber"
280
- assert meta["datagrabbers"][1]["class"] == "PatternDataladDataGrabber"