junifer 0.0.5.dev68__py3-none-any.whl → 0.0.5.dev86__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 (33) hide show
  1. junifer/_version.py +2 -2
  2. junifer/api/functions.py +1 -1
  3. junifer/configs/juseless/datagrabbers/tests/test_ucla.py +1 -3
  4. junifer/configs/juseless/datagrabbers/ucla.py +9 -9
  5. junifer/data/masks.py +10 -22
  6. junifer/data/parcellations.py +1 -1
  7. junifer/data/tests/test_masks.py +8 -28
  8. junifer/datagrabber/aomic/id1000.py +34 -38
  9. junifer/datagrabber/aomic/piop1.py +33 -37
  10. junifer/datagrabber/aomic/piop2.py +35 -39
  11. junifer/datagrabber/aomic/tests/test_id1000.py +10 -11
  12. junifer/datagrabber/aomic/tests/test_piop1.py +10 -11
  13. junifer/datagrabber/aomic/tests/test_piop2.py +10 -11
  14. junifer/datagrabber/datalad_base.py +10 -1
  15. junifer/datagrabber/dmcc13_benchmark.py +36 -54
  16. junifer/datagrabber/pattern.py +116 -46
  17. junifer/datagrabber/pattern_datalad.py +22 -12
  18. junifer/datagrabber/tests/test_datagrabber_utils.py +15 -9
  19. junifer/datagrabber/tests/test_dmcc13_benchmark.py +46 -19
  20. junifer/datagrabber/utils.py +127 -54
  21. junifer/datareader/default.py +91 -42
  22. junifer/preprocess/base.py +2 -2
  23. junifer/preprocess/confounds/fmriprep_confound_remover.py +44 -60
  24. junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py +72 -113
  25. junifer/testing/datagrabbers.py +5 -5
  26. junifer/testing/tests/test_partlycloudytesting_datagrabber.py +7 -7
  27. {junifer-0.0.5.dev68.dist-info → junifer-0.0.5.dev86.dist-info}/METADATA +1 -1
  28. {junifer-0.0.5.dev68.dist-info → junifer-0.0.5.dev86.dist-info}/RECORD +33 -33
  29. {junifer-0.0.5.dev68.dist-info → junifer-0.0.5.dev86.dist-info}/AUTHORS.rst +0 -0
  30. {junifer-0.0.5.dev68.dist-info → junifer-0.0.5.dev86.dist-info}/LICENSE.md +0 -0
  31. {junifer-0.0.5.dev68.dist-info → junifer-0.0.5.dev86.dist-info}/WHEEL +0 -0
  32. {junifer-0.0.5.dev68.dist-info → junifer-0.0.5.dev86.dist-info}/entry_points.txt +0 -0
  33. {junifer-0.0.5.dev68.dist-info → junifer-0.0.5.dev86.dist-info}/top_level.txt +0 -0
@@ -57,19 +57,19 @@ def test_DataladAOMICPIOP2(tasks: Optional[str]) -> None:
57
57
  assert out["BOLD"]["path"].exists()
58
58
  assert out["BOLD"]["path"].is_file()
59
59
 
60
- # asserts type "BOLD_confounds"
61
- assert "BOLD_confounds" in out
60
+ # asserts type BOLD.confounds
61
+ assert "confounds" in out["BOLD"]
62
62
 
63
63
  assert (
64
- out["BOLD_confounds"]["path"].name == f"{sub}_task-{new_task}_"
64
+ out["BOLD"]["confounds"]["path"].name == f"{sub}_task-{new_task}_"
65
65
  "desc-confounds_regressors.tsv"
66
66
  )
67
67
 
68
- assert out["BOLD_confounds"]["path"].exists()
69
- assert out["BOLD_confounds"]["path"].is_file()
68
+ assert out["BOLD"]["confounds"]["path"].exists()
69
+ assert out["BOLD"]["confounds"]["path"].is_file()
70
70
 
71
- # assert BOLD_mask
72
- assert out["BOLD_mask"]["path"].exists()
71
+ # assert BOLD.mask
72
+ assert out["BOLD"]["mask"]["path"].exists()
73
73
 
74
74
  # asserts type "T1w"
75
75
  assert "T1w" in out
@@ -82,8 +82,8 @@ def test_DataladAOMICPIOP2(tasks: Optional[str]) -> None:
82
82
  assert out["T1w"]["path"].exists()
83
83
  assert out["T1w"]["path"].is_file()
84
84
 
85
- # asserts T1w_mask
86
- assert out["T1w_mask"]["path"].exists()
85
+ # asserts T1w.mask
86
+ assert out["T1w"]["mask"]["path"].exists()
87
87
 
88
88
  # asserts type "VBM_CSF"
89
89
  assert "VBM_CSF" in out
@@ -141,13 +141,12 @@ def test_DataladAOMICPIOP2(tasks: Optional[str]) -> None:
141
141
  "types",
142
142
  [
143
143
  "BOLD",
144
- "BOLD_confounds",
145
144
  "T1w",
146
145
  "VBM_CSF",
147
146
  "VBM_GM",
148
147
  "VBM_WM",
149
148
  "DWI",
150
- ["BOLD", "BOLD_confounds"],
149
+ ["BOLD", "VBM_CSF"],
151
150
  ["T1w", "VBM_CSF"],
152
151
  ["VBM_GM", "VBM_WM"],
153
152
  ["DWI", "BOLD"],
@@ -176,7 +176,16 @@ class DataladDataGrabber(BaseDataGrabber):
176
176
  The unmodified input dictionary.
177
177
 
178
178
  """
179
- to_get = [v["path"] for v in out.values() if "path" in v]
179
+ to_get = []
180
+ for type_val in out.values():
181
+ # Iterate to check for nested "types" like mask
182
+ for k, v in type_val.items():
183
+ # Add base data type path
184
+ if k == "path":
185
+ to_get.append(v)
186
+ # Add nested data type path
187
+ if isinstance(v, dict) and "path" in v:
188
+ to_get.append(v["path"])
180
189
 
181
190
  if len(to_get) > 0:
182
191
  logger.debug(f"Getting {len(to_get)} files using datalad:")
@@ -25,17 +25,16 @@ class DMCC13Benchmark(PatternDataladDataGrabber):
25
25
  The directory where the datalad dataset will be cloned. If None,
26
26
  the datalad dataset will be cloned into a temporary directory
27
27
  (default None).
28
- types: {"BOLD", "BOLD_confounds", "BOLD_mask", "T1w", "T1w_mask", \
29
- "VBM_CSF", "VBM_GM", "VBM_WM", "Warp" (only if \
30
- "native_t1w = True")} or a list of the options, optional
28
+ types: {"BOLD", "T1w", "VBM_CSF", "VBM_GM", "VBM_WM"} or \
29
+ list of the options, optional
31
30
  DMCC data types. If None, all available data types are selected.
32
31
  (default None).
33
- sessions: {"ses-wave1bas", "ses-wave1pro", "ses-wave1rea"} or list of \
34
- the options, optional
32
+ sessions: {"ses-wave1bas", "ses-wave1pro", "ses-wave1rea"} or \
33
+ list of the options, optional
35
34
  DMCC sessions. If None, all available sessions are selected
36
35
  (default None).
37
36
  tasks: {"Rest", "Axcpt", "Cuedts", "Stern", "Stroop"} or \
38
- list of the options, optional
37
+ list of the options, optional
39
38
  DMCC task sessions. If None, all available task sessions are selected
40
39
  (default None).
41
40
  phase_encodings : {"AP", "PA"} or list of the options, optional
@@ -148,24 +147,23 @@ class DMCC13Benchmark(PatternDataladDataGrabber):
148
147
  "space-MNI152NLin2009cAsym_desc-preproc_bold.nii.gz"
149
148
  ),
150
149
  "space": "MNI152NLin2009cAsym",
151
- "mask_item": "BOLD_mask",
152
- },
153
- "BOLD_confounds": {
154
- "pattern": (
155
- "derivatives/fmriprep-1.3.2/{subject}/{session}/"
156
- "func/{subject}_{session}_task-{task}_acq-mb4"
157
- "{phase_encoding}_run-{run}_desc-confounds_regressors.tsv"
158
- ),
159
- "format": "fmriprep",
160
- },
161
- "BOLD_mask": {
162
- "pattern": (
163
- "derivatives/fmriprep-1.3.2/{subject}/{session}/"
164
- "/func/{subject}_{session}_task-{task}_acq-mb4"
165
- "{phase_encoding}_run-{run}_"
166
- "space-MNI152NLin2009cAsym_desc-brain_mask.nii.gz"
167
- ),
168
- "space": "MNI152NLin2009cAsym",
150
+ "mask": {
151
+ "pattern": (
152
+ "derivatives/fmriprep-1.3.2/{subject}/{session}/"
153
+ "/func/{subject}_{session}_task-{task}_acq-mb4"
154
+ "{phase_encoding}_run-{run}_"
155
+ "space-MNI152NLin2009cAsym_desc-brain_mask.nii.gz"
156
+ ),
157
+ "space": "MNI152NLin2009cAsym",
158
+ },
159
+ "confounds": {
160
+ "pattern": (
161
+ "derivatives/fmriprep-1.3.2/{subject}/{session}/"
162
+ "func/{subject}_{session}_task-{task}_acq-mb4"
163
+ "{phase_encoding}_run-{run}_desc-confounds_regressors.tsv"
164
+ ),
165
+ "format": "fmriprep",
166
+ },
169
167
  },
170
168
  "T1w": {
171
169
  "pattern": (
@@ -173,14 +171,13 @@ class DMCC13Benchmark(PatternDataladDataGrabber):
173
171
  "{subject}_space-MNI152NLin2009cAsym_desc-preproc_T1w.nii.gz"
174
172
  ),
175
173
  "space": "MNI152NLin2009cAsym",
176
- "mask_item": "T1w_mask",
177
- },
178
- "T1w_mask": {
179
- "pattern": (
180
- "derivatives/fmriprep-1.3.2/{subject}/anat/"
181
- "{subject}_space-MNI152NLin2009cAsym_desc-brain_mask.nii.gz"
182
- ),
183
- "space": "MNI152NLin2009cAsym",
174
+ "mask": {
175
+ "pattern": (
176
+ "derivatives/fmriprep-1.3.2/{subject}/anat/"
177
+ "{subject}_space-MNI152NLin2009cAsym_desc-brain_mask.nii.gz"
178
+ ),
179
+ "space": "MNI152NLin2009cAsym",
180
+ },
184
181
  },
185
182
  "VBM_CSF": {
186
183
  "pattern": (
@@ -216,14 +213,13 @@ class DMCC13Benchmark(PatternDataladDataGrabber):
216
213
  "{subject}_desc-preproc_T1w.nii.gz"
217
214
  ),
218
215
  "space": "native",
219
- "mask_item": "T1w_mask",
220
- },
221
- "T1w_mask": {
222
- "pattern": (
223
- "derivatives/fmriprep-1.3.2/{subject}/anat/"
224
- "{subject}_desc-brain_mask.nii.gz"
225
- ),
226
- "space": "native",
216
+ "mask": {
217
+ "pattern": (
218
+ "derivatives/fmriprep-1.3.2/{subject}/anat/"
219
+ "{subject}_desc-brain_mask.nii.gz"
220
+ ),
221
+ "space": "native",
222
+ },
227
223
  },
228
224
  "Warp": {
229
225
  "pattern": (
@@ -298,20 +294,6 @@ class DMCC13Benchmark(PatternDataladDataGrabber):
298
294
  phase_encoding=phase_encoding,
299
295
  run=run,
300
296
  )
301
- if out.get("BOLD"):
302
- out["BOLD"]["mask_item"] = "BOLD_mask"
303
- # Add space information
304
- out["BOLD"].update({"space": "MNI152NLin2009cAsym"})
305
- if out.get("T1w"):
306
- out["T1w"]["mask_item"] = "T1w_mask"
307
- # Add space information
308
- if self.native_t1w:
309
- out["T1w"].update({"space": "native"})
310
- else:
311
- out["T1w"].update({"space": "MNI152NLin2009cAsym"})
312
- if out.get("Warp"):
313
- # Add source space information
314
- out["Warp"].update({"src": "MNI152NLin2009cAsym"})
315
297
  return out
316
298
 
317
299
  def get_elements(self) -> List:
@@ -40,7 +40,12 @@ class PatternDataGrabber(BaseDataGrabber):
40
40
 
41
41
  {
42
42
  "mandatory": ["pattern", "space"],
43
- "optional": []
43
+ "optional": {
44
+ "mask": {
45
+ "mandatory": ["pattern", "space"],
46
+ "optional": []
47
+ }
48
+ }
44
49
  }
45
50
 
46
51
  * ``"T2w"`` :
@@ -49,7 +54,12 @@ class PatternDataGrabber(BaseDataGrabber):
49
54
 
50
55
  {
51
56
  "mandatory": ["pattern", "space"],
52
- "optional": []
57
+ "optional": {
58
+ "mask": {
59
+ "mandatory": ["pattern", "space"],
60
+ "optional": []
61
+ }
62
+ }
53
63
  }
54
64
 
55
65
  * ``"BOLD"`` :
@@ -58,7 +68,16 @@ class PatternDataGrabber(BaseDataGrabber):
58
68
 
59
69
  {
60
70
  "mandatory": ["pattern", "space"],
61
- "optional": ["mask_item"]
71
+ "optional": {
72
+ "mask": {
73
+ "mandatory": ["pattern", "space"],
74
+ "optional": []
75
+ }
76
+ "confounds": {
77
+ "mandatory": ["pattern", "format"],
78
+ "optional": []
79
+ }
80
+ }
62
81
  }
63
82
 
64
83
  * ``"Warp"`` :
@@ -70,15 +89,6 @@ class PatternDataGrabber(BaseDataGrabber):
70
89
  "optional": []
71
90
  }
72
91
 
73
- * ``"BOLD_confounds"`` :
74
-
75
- .. code-block:: none
76
-
77
- {
78
- "mandatory": ["pattern", "format"],
79
- "optional": []
80
- }
81
-
82
92
  * ``"VBM_GM"`` :
83
93
 
84
94
  .. code-block:: none
@@ -246,6 +256,64 @@ class PatternDataGrabber(BaseDataGrabber):
246
256
  )
247
257
  return pattern.format(**element)
248
258
 
259
+ def _get_path_from_patterns(
260
+ self, element: Dict, pattern: str, data_type: str
261
+ ) -> Path:
262
+ """Get path from resolved patterns.
263
+
264
+ Parameters
265
+ ----------
266
+ element : dict
267
+ The element to be used in the replacement.
268
+ pattern : str
269
+ The pattern to be replaced.
270
+ data_type : str
271
+ The data type of the pattern.
272
+
273
+ Returns
274
+ -------
275
+ pathlib.Path
276
+ The path for the resolved pattern.
277
+
278
+ Raises
279
+ ------
280
+ RuntimeError
281
+ If more than one file matches for a data type's pattern or
282
+ if no file matches for a data type's pattern or
283
+ if file cannot be accessed for an element.
284
+
285
+ """
286
+ # Replace element in the pattern for globbing
287
+ resolved_pattern = self._replace_patterns_glob(element, pattern)
288
+ # Resolve path for wildcard
289
+ if "*" in resolved_pattern:
290
+ t_matches = list(self.datadir.absolute().glob(resolved_pattern))
291
+ # Multiple matches
292
+ if len(t_matches) > 1:
293
+ raise_error(
294
+ f"More than one file matches for {element} / {data_type}:"
295
+ f" {t_matches}",
296
+ klass=RuntimeError,
297
+ )
298
+ # No matches
299
+ elif len(t_matches) == 0:
300
+ raise_error(
301
+ f"No file matches for {element} / {data_type}",
302
+ klass=RuntimeError,
303
+ )
304
+ path = t_matches[0]
305
+ else:
306
+ path = self.datadir / resolved_pattern
307
+ if not self.skip_file_check:
308
+ if not path.exists() and not path.is_symlink():
309
+ raise_error(
310
+ f"Cannot access {data_type} for {element}: "
311
+ f"File {path} does not exist",
312
+ klass=RuntimeError,
313
+ )
314
+
315
+ return path
316
+
249
317
  def get_element_keys(self) -> List[str]:
250
318
  """Get element keys.
251
319
 
@@ -279,47 +347,49 @@ class PatternDataGrabber(BaseDataGrabber):
279
347
  Dictionary of dictionaries for each type of data required for the
280
348
  specified element.
281
349
 
282
- Raises
283
- ------
284
- RuntimeError
285
- If more than one file matches for a data type's pattern or
286
- if no file matches for a data type's pattern or
287
- if file cannot be accessed for an element.
288
-
289
350
  """
290
351
  out = {}
291
352
  for t_type in self.types:
353
+ # Data type dictionary
292
354
  t_pattern = self.patterns[t_type]
293
- t_replace = self._replace_patterns_glob(
294
- element, t_pattern["pattern"]
295
- )
296
- if "*" in t_replace:
297
- t_matches = list(self.datadir.absolute().glob(t_replace))
298
- if len(t_matches) > 1:
299
- raise_error(
300
- f"More than one file matches for {element} / {t_type}:"
301
- f" {t_matches}",
302
- klass=RuntimeError,
355
+ # Copy data type dictionary in output
356
+ out[t_type] = t_pattern.copy()
357
+ # Iterate to check for nested "types" like mask
358
+ for k, v in t_pattern.items():
359
+ # Resolve pattern for base data type
360
+ if k == "pattern":
361
+ logger.info(f"Resolving path from pattern for {t_type}")
362
+ # Resolve pattern
363
+ base_data_type_pattern_path = self._get_path_from_patterns(
364
+ element=element,
365
+ pattern=v,
366
+ data_type=t_type,
303
367
  )
304
- elif len(t_matches) == 0:
305
- raise_error(
306
- f"No file matches for {element} / {t_type}",
307
- klass=RuntimeError,
368
+ # Remove pattern key
369
+ out[t_type].pop("pattern")
370
+ # Add path key
371
+ out[t_type].update({"path": base_data_type_pattern_path})
372
+ # Resolve pattern for nested data type
373
+ if isinstance(v, dict) and "pattern" in v:
374
+ # Set nested type key for easier access
375
+ t_nested_type = f"{t_type}.{k}"
376
+ logger.info(
377
+ f"Resolving path from pattern for {t_nested_type}"
308
378
  )
309
- t_out = t_matches[0]
310
- else:
311
- t_out = self.datadir / t_replace
312
- if not self.skip_file_check:
313
- if not t_out.exists() and not t_out.is_symlink():
314
- raise_error(
315
- f"Cannot access {t_type} for {element}: "
316
- f"File {t_out} does not exist",
317
- klass=RuntimeError,
379
+ # Resolve pattern
380
+ nested_data_type_pattern_path = (
381
+ self._get_path_from_patterns(
382
+ element=element,
383
+ pattern=v["pattern"],
384
+ data_type=t_nested_type,
318
385
  )
319
- # Update path for the element
320
- out[t_type] = t_pattern.copy() # copy data type dictionary
321
- out[t_type].pop("pattern") # remove pattern key
322
- out[t_type].update({"path": t_out}) # add path key
386
+ )
387
+ # Remove pattern key
388
+ out[t_type][k].pop("pattern")
389
+ # Add path key
390
+ out[t_type][k].update(
391
+ {"path": nested_data_type_pattern_path}
392
+ )
323
393
 
324
394
  return out
325
395
 
@@ -32,7 +32,12 @@ class PatternDataladDataGrabber(DataladDataGrabber, PatternDataGrabber):
32
32
 
33
33
  {
34
34
  "mandatory": ["pattern", "space"],
35
- "optional": []
35
+ "optional": {
36
+ "mask": {
37
+ "mandatory": ["pattern", "space"],
38
+ "optional": []
39
+ }
40
+ }
36
41
  }
37
42
 
38
43
  * ``"T2w"`` :
@@ -41,7 +46,12 @@ class PatternDataladDataGrabber(DataladDataGrabber, PatternDataGrabber):
41
46
 
42
47
  {
43
48
  "mandatory": ["pattern", "space"],
44
- "optional": []
49
+ "optional": {
50
+ "mask": {
51
+ "mandatory": ["pattern", "space"],
52
+ "optional": []
53
+ }
54
+ }
45
55
  }
46
56
 
47
57
  * ``"BOLD"`` :
@@ -50,7 +60,16 @@ class PatternDataladDataGrabber(DataladDataGrabber, PatternDataGrabber):
50
60
 
51
61
  {
52
62
  "mandatory": ["pattern", "space"],
53
- "optional": ["mask_item"]
63
+ "optional": {
64
+ "mask": {
65
+ "mandatory": ["pattern", "space"],
66
+ "optional": []
67
+ }
68
+ "confounds": {
69
+ "mandatory": ["pattern", "format"],
70
+ "optional": []
71
+ }
72
+ }
54
73
  }
55
74
 
56
75
  * ``"Warp"`` :
@@ -62,15 +81,6 @@ class PatternDataladDataGrabber(DataladDataGrabber, PatternDataGrabber):
62
81
  "optional": []
63
82
  }
64
83
 
65
- * ``"BOLD_confounds"`` :
66
-
67
- .. code-block:: none
68
-
69
- {
70
- "mandatory": ["pattern", "format"],
71
- "optional": []
72
- }
73
-
74
84
  * ``"VBM_GM"`` :
75
85
 
76
86
  .. code-block:: none
@@ -151,12 +151,18 @@ def test_validate_replacements(
151
151
  pytest.raises(KeyError, match="Mandatory key"),
152
152
  ),
153
153
  (
154
- ["BOLD_confounds"],
154
+ ["BOLD"],
155
155
  {
156
- "BOLD_confounds": {
157
- "pattern": "{subject}/func/{subject}_confounds.tsv",
158
- "format": "fmriprep",
156
+ "BOLD": {
157
+ "pattern": (
158
+ "{subject}/func/{subject}_task-rest_bold.nii.gz"
159
+ ),
159
160
  "space": "MNINLin6Asym",
161
+ "confounds": {
162
+ "pattern": "{subject}/func/{subject}_confounds.tsv",
163
+ "format": "fmriprep",
164
+ },
165
+ "zip": "zap",
160
166
  },
161
167
  },
162
168
  pytest.raises(RuntimeError, match="not accepted"),
@@ -172,7 +178,7 @@ def test_validate_replacements(
172
178
  pytest.raises(ValueError, match="following a replacement"),
173
179
  ),
174
180
  (
175
- ["T1w", "T2w", "BOLD", "BOLD_confounds"],
181
+ ["T1w", "T2w", "BOLD"],
176
182
  {
177
183
  "T1w": {
178
184
  "pattern": "{subject}/anat/{subject}_T1w.nii.gz",
@@ -187,10 +193,10 @@ def test_validate_replacements(
187
193
  "{subject}/func/{subject}_task-rest_bold.nii.gz"
188
194
  ),
189
195
  "space": "MNI152NLin6Asym",
190
- },
191
- "BOLD_confounds": {
192
- "pattern": "{subject}/func/{subject}_confounds.tsv",
193
- "format": "fmriprep",
196
+ "confounds": {
197
+ "pattern": "{subject}/func/{subject}_confounds.tsv",
198
+ "format": "fmriprep",
199
+ },
194
200
  },
195
201
  },
196
202
  nullcontext(),
@@ -93,13 +93,10 @@ def test_DMCC13Benchmark(
93
93
  # Available data types
94
94
  data_types = [
95
95
  "BOLD",
96
- "BOLD_confounds",
97
- "BOLD_mask",
98
96
  "VBM_CSF",
99
97
  "VBM_GM",
100
98
  "VBM_WM",
101
99
  "T1w",
102
- "T1w_mask",
103
100
  ]
104
101
  # Add Warp if native T1w is accessed
105
102
  if native_t1w:
@@ -111,14 +108,6 @@ def test_DMCC13Benchmark(
111
108
  f"sub-01_{ses}_task-{task}_acq-mb4{phase}_run-{run}_"
112
109
  "space-MNI152NLin2009cAsym_desc-preproc_bold.nii.gz"
113
110
  ),
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
- ),
122
111
  "sub-01_space-MNI152NLin2009cAsym_label-CSF_probseg.nii.gz",
123
112
  "sub-01_space-MNI152NLin2009cAsym_label-GM_probseg.nii.gz",
124
113
  "sub-01_space-MNI152NLin2009cAsym_label-WM_probseg.nii.gz",
@@ -127,16 +116,12 @@ def test_DMCC13Benchmark(
127
116
  data_file_names.extend(
128
117
  [
129
118
  "sub-01_desc-preproc_T1w.nii.gz",
130
- "sub-01_desc-brain_mask.nii.gz",
131
119
  "sub-01_from-MNI152NLin2009cAsym_to-T1w_mode-image_xfm.h5",
132
120
  ]
133
121
  )
134
122
  else:
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
- ]
123
+ data_file_names.append(
124
+ "sub-01_space-MNI152NLin2009cAsym_desc-preproc_T1w.nii.gz"
140
125
  )
141
126
 
142
127
  for data_type, data_file_name in zip(data_types, data_file_names):
@@ -151,6 +136,48 @@ def test_DMCC13Benchmark(
151
136
  # Assert metadata
152
137
  assert "meta" in out[data_type]
153
138
 
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
+
154
181
 
155
182
  @pytest.mark.parametrize(
156
183
  "types, native_t1w",
@@ -165,8 +192,8 @@ def test_DMCC13Benchmark(
165
192
  ("VBM_GM", False),
166
193
  ("VBM_WM", True),
167
194
  ("VBM_WM", False),
168
- (["BOLD", "BOLD_confounds"], True),
169
- (["BOLD", "BOLD_confounds"], False),
195
+ (["BOLD", "VBM_CSF"], True),
196
+ (["BOLD", "VBM_CSF"], False),
170
197
  (["T1w", "VBM_CSF"], True),
171
198
  (["T1w", "VBM_CSF"], False),
172
199
  (["VBM_GM", "VBM_WM"], True),