junifer 0.0.3.dev188__py3-none-any.whl → 0.0.4__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 (178) hide show
  1. junifer/_version.py +14 -2
  2. junifer/api/cli.py +162 -17
  3. junifer/api/functions.py +87 -419
  4. junifer/api/parser.py +24 -0
  5. junifer/api/queue_context/__init__.py +8 -0
  6. junifer/api/queue_context/gnu_parallel_local_adapter.py +258 -0
  7. junifer/api/queue_context/htcondor_adapter.py +365 -0
  8. junifer/api/queue_context/queue_context_adapter.py +60 -0
  9. junifer/api/queue_context/tests/test_gnu_parallel_local_adapter.py +192 -0
  10. junifer/api/queue_context/tests/test_htcondor_adapter.py +257 -0
  11. junifer/api/res/afni/run_afni_docker.sh +6 -6
  12. junifer/api/res/ants/ResampleImage +3 -0
  13. junifer/api/res/ants/antsApplyTransforms +3 -0
  14. junifer/api/res/ants/antsApplyTransformsToPoints +3 -0
  15. junifer/api/res/ants/run_ants_docker.sh +39 -0
  16. junifer/api/res/fsl/applywarp +3 -0
  17. junifer/api/res/fsl/flirt +3 -0
  18. junifer/api/res/fsl/img2imgcoord +3 -0
  19. junifer/api/res/fsl/run_fsl_docker.sh +39 -0
  20. junifer/api/res/fsl/std2imgcoord +3 -0
  21. junifer/api/res/run_conda.sh +4 -4
  22. junifer/api/res/run_venv.sh +22 -0
  23. junifer/api/tests/data/partly_cloudy_agg_mean_tian.yml +16 -0
  24. junifer/api/tests/test_api_utils.py +21 -3
  25. junifer/api/tests/test_cli.py +232 -9
  26. junifer/api/tests/test_functions.py +211 -439
  27. junifer/api/tests/test_parser.py +1 -1
  28. junifer/configs/juseless/datagrabbers/aomic_id1000_vbm.py +6 -1
  29. junifer/configs/juseless/datagrabbers/camcan_vbm.py +6 -1
  30. junifer/configs/juseless/datagrabbers/ixi_vbm.py +6 -1
  31. junifer/configs/juseless/datagrabbers/tests/test_ucla.py +8 -8
  32. junifer/configs/juseless/datagrabbers/ucla.py +44 -26
  33. junifer/configs/juseless/datagrabbers/ukb_vbm.py +6 -1
  34. junifer/data/VOIs/meta/AutobiographicalMemory_VOIs.txt +23 -0
  35. junifer/data/VOIs/meta/Power2013_MNI_VOIs.tsv +264 -0
  36. junifer/data/__init__.py +4 -0
  37. junifer/data/coordinates.py +298 -31
  38. junifer/data/masks.py +360 -28
  39. junifer/data/parcellations.py +621 -188
  40. junifer/data/template_spaces.py +190 -0
  41. junifer/data/tests/test_coordinates.py +34 -3
  42. junifer/data/tests/test_data_utils.py +1 -0
  43. junifer/data/tests/test_masks.py +202 -86
  44. junifer/data/tests/test_parcellations.py +266 -55
  45. junifer/data/tests/test_template_spaces.py +104 -0
  46. junifer/data/utils.py +4 -2
  47. junifer/datagrabber/__init__.py +1 -0
  48. junifer/datagrabber/aomic/id1000.py +111 -70
  49. junifer/datagrabber/aomic/piop1.py +116 -53
  50. junifer/datagrabber/aomic/piop2.py +116 -53
  51. junifer/datagrabber/aomic/tests/test_id1000.py +27 -27
  52. junifer/datagrabber/aomic/tests/test_piop1.py +27 -27
  53. junifer/datagrabber/aomic/tests/test_piop2.py +27 -27
  54. junifer/datagrabber/base.py +62 -10
  55. junifer/datagrabber/datalad_base.py +0 -2
  56. junifer/datagrabber/dmcc13_benchmark.py +372 -0
  57. junifer/datagrabber/hcp1200/datalad_hcp1200.py +5 -0
  58. junifer/datagrabber/hcp1200/hcp1200.py +30 -13
  59. junifer/datagrabber/pattern.py +133 -27
  60. junifer/datagrabber/pattern_datalad.py +111 -13
  61. junifer/datagrabber/tests/test_base.py +57 -6
  62. junifer/datagrabber/tests/test_datagrabber_utils.py +204 -76
  63. junifer/datagrabber/tests/test_datalad_base.py +0 -6
  64. junifer/datagrabber/tests/test_dmcc13_benchmark.py +256 -0
  65. junifer/datagrabber/tests/test_multiple.py +43 -10
  66. junifer/datagrabber/tests/test_pattern.py +125 -178
  67. junifer/datagrabber/tests/test_pattern_datalad.py +44 -25
  68. junifer/datagrabber/utils.py +151 -16
  69. junifer/datareader/default.py +36 -10
  70. junifer/external/nilearn/junifer_nifti_spheres_masker.py +6 -0
  71. junifer/markers/base.py +25 -16
  72. junifer/markers/collection.py +35 -16
  73. junifer/markers/complexity/__init__.py +27 -0
  74. junifer/markers/complexity/complexity_base.py +149 -0
  75. junifer/markers/complexity/hurst_exponent.py +136 -0
  76. junifer/markers/complexity/multiscale_entropy_auc.py +140 -0
  77. junifer/markers/complexity/perm_entropy.py +132 -0
  78. junifer/markers/complexity/range_entropy.py +136 -0
  79. junifer/markers/complexity/range_entropy_auc.py +145 -0
  80. junifer/markers/complexity/sample_entropy.py +134 -0
  81. junifer/markers/complexity/tests/test_complexity_base.py +19 -0
  82. junifer/markers/complexity/tests/test_hurst_exponent.py +69 -0
  83. junifer/markers/complexity/tests/test_multiscale_entropy_auc.py +68 -0
  84. junifer/markers/complexity/tests/test_perm_entropy.py +68 -0
  85. junifer/markers/complexity/tests/test_range_entropy.py +69 -0
  86. junifer/markers/complexity/tests/test_range_entropy_auc.py +69 -0
  87. junifer/markers/complexity/tests/test_sample_entropy.py +68 -0
  88. junifer/markers/complexity/tests/test_weighted_perm_entropy.py +68 -0
  89. junifer/markers/complexity/weighted_perm_entropy.py +133 -0
  90. junifer/markers/falff/_afni_falff.py +153 -0
  91. junifer/markers/falff/_junifer_falff.py +142 -0
  92. junifer/markers/falff/falff_base.py +91 -84
  93. junifer/markers/falff/falff_parcels.py +61 -45
  94. junifer/markers/falff/falff_spheres.py +64 -48
  95. junifer/markers/falff/tests/test_falff_parcels.py +89 -121
  96. junifer/markers/falff/tests/test_falff_spheres.py +92 -127
  97. junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +1 -0
  98. junifer/markers/functional_connectivity/edge_functional_connectivity_parcels.py +1 -0
  99. junifer/markers/functional_connectivity/functional_connectivity_base.py +1 -0
  100. junifer/markers/functional_connectivity/tests/test_crossparcellation_functional_connectivity.py +46 -44
  101. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_parcels.py +34 -39
  102. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_spheres.py +40 -52
  103. junifer/markers/functional_connectivity/tests/test_functional_connectivity_parcels.py +62 -70
  104. junifer/markers/functional_connectivity/tests/test_functional_connectivity_spheres.py +99 -85
  105. junifer/markers/parcel_aggregation.py +60 -38
  106. junifer/markers/reho/_afni_reho.py +192 -0
  107. junifer/markers/reho/_junifer_reho.py +281 -0
  108. junifer/markers/reho/reho_base.py +69 -34
  109. junifer/markers/reho/reho_parcels.py +26 -16
  110. junifer/markers/reho/reho_spheres.py +23 -9
  111. junifer/markers/reho/tests/test_reho_parcels.py +93 -92
  112. junifer/markers/reho/tests/test_reho_spheres.py +88 -86
  113. junifer/markers/sphere_aggregation.py +54 -9
  114. junifer/markers/temporal_snr/temporal_snr_base.py +1 -0
  115. junifer/markers/temporal_snr/tests/test_temporal_snr_parcels.py +38 -37
  116. junifer/markers/temporal_snr/tests/test_temporal_snr_spheres.py +34 -38
  117. junifer/markers/tests/test_collection.py +43 -42
  118. junifer/markers/tests/test_ets_rss.py +29 -37
  119. junifer/markers/tests/test_parcel_aggregation.py +587 -468
  120. junifer/markers/tests/test_sphere_aggregation.py +209 -157
  121. junifer/markers/utils.py +2 -40
  122. junifer/onthefly/read_transform.py +13 -6
  123. junifer/pipeline/__init__.py +1 -0
  124. junifer/pipeline/pipeline_step_mixin.py +105 -41
  125. junifer/pipeline/registry.py +17 -0
  126. junifer/pipeline/singleton.py +45 -0
  127. junifer/pipeline/tests/test_pipeline_step_mixin.py +139 -51
  128. junifer/pipeline/tests/test_update_meta_mixin.py +1 -0
  129. junifer/pipeline/tests/test_workdir_manager.py +104 -0
  130. junifer/pipeline/update_meta_mixin.py +8 -2
  131. junifer/pipeline/utils.py +154 -15
  132. junifer/pipeline/workdir_manager.py +246 -0
  133. junifer/preprocess/__init__.py +3 -0
  134. junifer/preprocess/ants/__init__.py +4 -0
  135. junifer/preprocess/ants/ants_apply_transforms_warper.py +185 -0
  136. junifer/preprocess/ants/tests/test_ants_apply_transforms_warper.py +56 -0
  137. junifer/preprocess/base.py +96 -69
  138. junifer/preprocess/bold_warper.py +265 -0
  139. junifer/preprocess/confounds/fmriprep_confound_remover.py +91 -134
  140. junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py +106 -111
  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/tests/test_bold_warper.py +159 -0
  145. junifer/preprocess/tests/test_preprocess_base.py +6 -6
  146. junifer/preprocess/warping/__init__.py +6 -0
  147. junifer/preprocess/warping/_ants_warper.py +167 -0
  148. junifer/preprocess/warping/_fsl_warper.py +109 -0
  149. junifer/preprocess/warping/space_warper.py +213 -0
  150. junifer/preprocess/warping/tests/test_space_warper.py +198 -0
  151. junifer/stats.py +18 -4
  152. junifer/storage/base.py +9 -1
  153. junifer/storage/hdf5.py +8 -3
  154. junifer/storage/pandas_base.py +2 -1
  155. junifer/storage/sqlite.py +1 -0
  156. junifer/storage/tests/test_hdf5.py +2 -1
  157. junifer/storage/tests/test_sqlite.py +8 -8
  158. junifer/storage/tests/test_utils.py +6 -6
  159. junifer/storage/utils.py +1 -0
  160. junifer/testing/datagrabbers.py +11 -7
  161. junifer/testing/utils.py +1 -0
  162. junifer/tests/test_stats.py +2 -0
  163. junifer/utils/__init__.py +1 -0
  164. junifer/utils/helpers.py +53 -0
  165. junifer/utils/logging.py +14 -3
  166. junifer/utils/tests/test_helpers.py +35 -0
  167. {junifer-0.0.3.dev188.dist-info → junifer-0.0.4.dist-info}/METADATA +59 -28
  168. junifer-0.0.4.dist-info/RECORD +257 -0
  169. {junifer-0.0.3.dev188.dist-info → junifer-0.0.4.dist-info}/WHEEL +1 -1
  170. junifer/markers/falff/falff_estimator.py +0 -334
  171. junifer/markers/falff/tests/test_falff_estimator.py +0 -238
  172. junifer/markers/reho/reho_estimator.py +0 -515
  173. junifer/markers/reho/tests/test_reho_estimator.py +0 -260
  174. junifer-0.0.3.dev188.dist-info/RECORD +0 -199
  175. {junifer-0.0.3.dev188.dist-info → junifer-0.0.4.dist-info}/AUTHORS.rst +0 -0
  176. {junifer-0.0.3.dev188.dist-info → junifer-0.0.4.dist-info}/LICENSE.md +0 -0
  177. {junifer-0.0.3.dev188.dist-info → junifer-0.0.4.dist-info}/entry_points.txt +0 -0
  178. {junifer-0.0.3.dev188.dist-info → junifer-0.0.4.dist-info}/top_level.txt +0 -0
@@ -3,6 +3,9 @@
3
3
  # Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
4
4
  # License: AGPL
5
5
 
6
+ from contextlib import nullcontext
7
+ from typing import ContextManager, Dict, List, Union
8
+
6
9
  import pytest
7
10
 
8
11
  from junifer.datagrabber.utils import (
@@ -12,79 +15,204 @@ from junifer.datagrabber.utils import (
12
15
  )
13
16
 
14
17
 
15
- def test_validate_types() -> None:
16
- """Test validation of types."""
17
- with pytest.raises(TypeError, match="must be a list"):
18
- validate_types("wrong") # type: ignore
19
- with pytest.raises(TypeError, match="must be a list of strings"):
20
- validate_types([1]) # type: ignore
21
-
22
- validate_types(["T1w", "BOLD"])
23
-
24
-
25
- def test_validate_replacements() -> None:
26
- """Test validation of replacements."""
27
- with pytest.raises(TypeError, match="must be a list"):
28
- validate_replacements("wrong", "also wrong") # type: ignore
29
- with pytest.raises(TypeError, match="must be a dict"):
30
- validate_replacements(["correct"], "wrong") # type: ignore
31
-
32
- patterns = {
33
- "T1w": "{subject}/anat/{subject}_T1w.nii.gz",
34
- "BOLD": "{subject}/func/{subject}_task-rest_bold.nii.gz",
35
- }
36
-
37
- with pytest.raises(TypeError, match="must be a list of strings"):
38
- validate_replacements([1], patterns) # type: ignore
39
-
40
- with pytest.raises(ValueError, match="is not part of"):
41
- validate_replacements(["session"], patterns)
42
-
43
- wrong_patterns = {
44
- "T1w": "{subject}/anat/_T1w.nii.gz",
45
- "BOLD": "{session}/func/_task-rest_bold.nii.gz",
46
- }
47
-
48
- with pytest.raises(ValueError, match="At least one pattern"):
49
- validate_replacements(["subject", "session"], wrong_patterns)
50
-
51
- validate_replacements(["subject"], patterns)
52
-
53
-
54
- def test_validate_patterns() -> None:
55
- """Test validation of patterns."""
56
- types = ["T1w", "BOLD"]
57
- with pytest.raises(TypeError, match="must be a dict"):
58
- validate_patterns(types, "wrong") # type: ignore
59
-
60
- wrongpatterns = {
61
- "T1w": "{subject}/anat/{subject}_T1w.nii.gz",
62
- }
63
-
64
- with pytest.raises(
65
- ValueError, match="Length of `types` more than that of `patterns`."
66
- ):
67
- validate_patterns(types, wrongpatterns) # type: ignore
68
-
69
- wrongpatterns = {
70
- "T1w": "{subject}/anat/{subject}_T1w.nii.gz",
71
- "T2": "{subject}/anat/{subject}_T2.nii.gz",
72
- }
73
-
74
- with pytest.raises(ValueError, match="contain all"):
75
- validate_patterns(types, wrongpatterns) # type: ignore
76
-
77
- patterns = {
78
- "T1w": "{subject}/anat/{subject}_T1w.nii.gz",
79
- "BOLD": "{subject}/func/{subject}_task-rest_bold.nii.gz",
80
- }
81
-
82
- wrongpatterns = {
83
- "T1w": "{subject}/anat/{subject}*.nii",
84
- "BOLD": "{subject}/func/{subject}_task-rest_bold.nii.gz",
85
- }
86
-
87
- with pytest.raises(ValueError, match="following a replacement"):
88
- validate_patterns(types, wrongpatterns)
89
-
90
- validate_patterns(types, patterns)
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
@@ -26,12 +26,6 @@ _testing_dataset = {
26
26
  }
27
27
 
28
28
 
29
- def test_DataladDataGrabber_abstractness() -> None:
30
- """Test DataladDataGrabber is abstract base class."""
31
- with pytest.raises(TypeError, match=r"abstract"):
32
- DataladDataGrabber() # type: ignore
33
-
34
-
35
29
  @pytest.fixture
36
30
  def concrete_datagrabber() -> Type[DataladDataGrabber]:
37
31
  """Return a concrete datalad-based DataGrabber.
@@ -0,0 +1,256 @@
1
+ """Provide tests for DMCC13Benchmark DataGrabber."""
2
+
3
+ # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
+ # License: AGPL
5
+
6
+ from typing import List, Optional, Union
7
+
8
+ import pytest
9
+
10
+ from junifer.datagrabber import DMCC13Benchmark
11
+
12
+
13
+ URI = "https://gin.g-node.org/synchon/datalad-example-dmcc13-benchmark"
14
+
15
+
16
+ @pytest.mark.parametrize(
17
+ "sessions, tasks, phase_encodings, runs, native_t1w",
18
+ [
19
+ (None, None, None, None, False),
20
+ ("ses-wave1bas", "Rest", "AP", "1", False),
21
+ ("ses-wave1bas", "Axcpt", "AP", "1", False),
22
+ ("ses-wave1bas", "Cuedts", "AP", "1", False),
23
+ ("ses-wave1bas", "Stern", "AP", "1", False),
24
+ ("ses-wave1bas", "Stroop", "AP", "1", False),
25
+ ("ses-wave1bas", "Rest", "PA", "2", False),
26
+ ("ses-wave1bas", "Axcpt", "PA", "2", False),
27
+ ("ses-wave1bas", "Cuedts", "PA", "2", False),
28
+ ("ses-wave1bas", "Stern", "PA", "2", False),
29
+ ("ses-wave1bas", "Stroop", "PA", "2", False),
30
+ ("ses-wave1bas", "Rest", "AP", "1", True),
31
+ ("ses-wave1bas", "Axcpt", "AP", "1", True),
32
+ ("ses-wave1bas", "Cuedts", "AP", "1", True),
33
+ ("ses-wave1bas", "Stern", "AP", "1", True),
34
+ ("ses-wave1bas", "Stroop", "AP", "1", True),
35
+ ("ses-wave1bas", "Rest", "PA", "2", True),
36
+ ("ses-wave1bas", "Axcpt", "PA", "2", True),
37
+ ("ses-wave1bas", "Cuedts", "PA", "2", True),
38
+ ("ses-wave1bas", "Stern", "PA", "2", True),
39
+ ("ses-wave1bas", "Stroop", "PA", "2", True),
40
+ ("ses-wave1pro", "Rest", "AP", "1", False),
41
+ ("ses-wave1pro", "Rest", "PA", "2", False),
42
+ ("ses-wave1pro", "Rest", "AP", "1", True),
43
+ ("ses-wave1pro", "Rest", "PA", "2", True),
44
+ ("ses-wave1rea", "Rest", "AP", "1", False),
45
+ ("ses-wave1rea", "Rest", "PA", "2", False),
46
+ ("ses-wave1rea", "Rest", "AP", "1", True),
47
+ ("ses-wave1rea", "Rest", "PA", "2", True),
48
+ ],
49
+ )
50
+ def test_DMCC13Benchmark(
51
+ sessions: Optional[str],
52
+ tasks: Optional[str],
53
+ phase_encodings: Optional[str],
54
+ runs: Optional[str],
55
+ native_t1w: bool,
56
+ ) -> None:
57
+ """Test DMCC13Benchmark DataGrabber.
58
+
59
+ Parameters
60
+ ----------
61
+ sessions : str or None
62
+ The parametrized session values.
63
+ tasks : str or None
64
+ The parametrized task values.
65
+ phase_encodings : str or None
66
+ The parametrized phase encoding values.
67
+ runs : str or None
68
+ The parametrized run values.
69
+ native_t1w : bool
70
+ The parametrized values for fetching native T1w.
71
+
72
+ """
73
+ dg = DMCC13Benchmark(
74
+ sessions=sessions,
75
+ tasks=tasks,
76
+ phase_encodings=phase_encodings,
77
+ runs=runs,
78
+ native_t1w=native_t1w,
79
+ )
80
+ # Set URI to Gin
81
+ dg.uri = URI
82
+
83
+ with dg:
84
+ # Get all elements
85
+ all_elements = dg.get_elements()
86
+ # Get test element
87
+ test_element = all_elements[0]
88
+ # Get test element's access values
89
+ _, ses, task, phase, run = test_element
90
+ # Access data
91
+ out = dg[("sub-01", ses, task, phase, run)]
92
+
93
+ # Available data types
94
+ data_types = [
95
+ "BOLD",
96
+ "BOLD_confounds",
97
+ "BOLD_mask",
98
+ "VBM_CSF",
99
+ "VBM_GM",
100
+ "VBM_WM",
101
+ "T1w",
102
+ "T1w_mask",
103
+ ]
104
+ # Add Warp if native T1w is accessed
105
+ if native_t1w:
106
+ data_types.append("Warp")
107
+
108
+ # Data type file name formats
109
+ data_file_names = [
110
+ (
111
+ f"sub-01_{ses}_task-{task}_acq-mb4{phase}_run-{run}_"
112
+ "space-MNI152NLin2009cAsym_desc-preproc_bold.nii.gz"
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
+ ),
122
+ "sub-01_space-MNI152NLin2009cAsym_label-CSF_probseg.nii.gz",
123
+ "sub-01_space-MNI152NLin2009cAsym_label-GM_probseg.nii.gz",
124
+ "sub-01_space-MNI152NLin2009cAsym_label-WM_probseg.nii.gz",
125
+ ]
126
+ if native_t1w:
127
+ data_file_names.extend(
128
+ [
129
+ "sub-01_desc-preproc_T1w.nii.gz",
130
+ "sub-01_desc-brain_mask.nii.gz",
131
+ "sub-01_from-MNI152NLin2009cAsym_to-T1w_mode-image_xfm.h5",
132
+ ]
133
+ )
134
+ 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
+ ]
140
+ )
141
+
142
+ for data_type, data_file_name in zip(data_types, data_file_names):
143
+ # Assert data type
144
+ assert data_type in out
145
+ # Assert data file path exists
146
+ assert out[data_type]["path"].exists()
147
+ # Assert data file path is a file
148
+ assert out[data_type]["path"].is_file()
149
+ # Assert data file name
150
+ assert out[data_type]["path"].name == data_file_name
151
+ # Assert metadata
152
+ assert "meta" in out[data_type]
153
+
154
+
155
+ @pytest.mark.parametrize(
156
+ "types, native_t1w",
157
+ [
158
+ ("BOLD", True),
159
+ ("BOLD", False),
160
+ ("T1w", True),
161
+ ("T1w", False),
162
+ ("VBM_CSF", True),
163
+ ("VBM_CSF", False),
164
+ ("VBM_GM", True),
165
+ ("VBM_GM", False),
166
+ ("VBM_WM", True),
167
+ ("VBM_WM", False),
168
+ (["BOLD", "BOLD_confounds"], True),
169
+ (["BOLD", "BOLD_confounds"], False),
170
+ (["T1w", "VBM_CSF"], True),
171
+ (["T1w", "VBM_CSF"], False),
172
+ (["VBM_GM", "VBM_WM"], True),
173
+ (["VBM_GM", "VBM_WM"], False),
174
+ ],
175
+ )
176
+ def test_DMCC13Benchmark_partial_data_access(
177
+ types: Union[str, List[str]],
178
+ native_t1w: bool,
179
+ ) -> None:
180
+ """Test DMCC13Benchmark DataGrabber partial data access.
181
+
182
+ Parameters
183
+ ----------
184
+ types : str or list of str
185
+ The parametrized types.
186
+ native_t1w : bool
187
+ The parametrized values for fetching native T1w.
188
+
189
+ """
190
+ dg = DMCC13Benchmark(types=types, native_t1w=native_t1w)
191
+ # Set URI to Gin
192
+ dg.uri = URI
193
+
194
+ with dg:
195
+ # Get all elements
196
+ all_elements = dg.get_elements()
197
+ # Get test element
198
+ test_element = all_elements[0]
199
+ # Get test element's access values
200
+ _, ses, task, phase, run = test_element
201
+ # Access data
202
+ out = dg[("sub-01", ses, task, phase, run)]
203
+ # Assert data type
204
+ if isinstance(types, list):
205
+ for type_ in types:
206
+ assert type_ in out
207
+ else:
208
+ assert types in out
209
+
210
+
211
+ def test_DMCC13Benchmark_incorrect_data_type() -> None:
212
+ """Test DMCC13Benchmark DataGrabber incorrect data type."""
213
+ with pytest.raises(
214
+ ValueError, match="`patterns` must contain all `types`"
215
+ ):
216
+ _ = DMCC13Benchmark(types="Orcus")
217
+
218
+
219
+ def test_DMCC13Benchmark_invalid_sessions():
220
+ """Test DMCC13Benchmark DataGrabber invalid sessions."""
221
+ with pytest.raises(
222
+ ValueError,
223
+ match=("phonyses is not a valid session in " "the DMCC dataset"),
224
+ ):
225
+ DMCC13Benchmark(sessions="phonyses")
226
+
227
+
228
+ def test_DMCC13Benchmark_invalid_tasks():
229
+ """Test DMCC13Benchmark DataGrabber invalid tasks."""
230
+ with pytest.raises(
231
+ ValueError,
232
+ match=(
233
+ "thisisnotarealtask is not a valid task in " "the DMCC dataset"
234
+ ),
235
+ ):
236
+ DMCC13Benchmark(tasks="thisisnotarealtask")
237
+
238
+
239
+ def test_DMCC13Benchmark_phase_encodings():
240
+ """Test DMCC13Benchmark DataGrabber invalid phase encodings."""
241
+ with pytest.raises(
242
+ ValueError,
243
+ match=(
244
+ "moonphase is not a valid phase encoding in " "the DMCC dataset"
245
+ ),
246
+ ):
247
+ DMCC13Benchmark(phase_encodings="moonphase")
248
+
249
+
250
+ def test_DMCC13Benchmark_runs():
251
+ """Test DMCC13Benchmark DataGrabber invalid runs."""
252
+ with pytest.raises(
253
+ ValueError,
254
+ match=("cerebralrun is not a valid run in " "the DMCC dataset"),
255
+ ):
256
+ DMCC13Benchmark(runs="cerebralrun")
@@ -26,11 +26,21 @@ def test_MultipleDataGrabber() -> None:
26
26
  rootdir = "example_bids_ses"
27
27
  replacements = ["subject", "session"]
28
28
  pattern1 = {
29
- "T1w": "{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz",
29
+ "T1w": {
30
+ "pattern": (
31
+ "{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz"
32
+ ),
33
+ "space": "native",
34
+ },
30
35
  }
31
36
  pattern2 = {
32
- "BOLD": "{subject}/{session}/func/"
33
- "{subject}_{session}_task-rest_bold.nii.gz",
37
+ "BOLD": {
38
+ "pattern": (
39
+ "{subject}/{session}/func/"
40
+ "{subject}_{session}_task-rest_bold.nii.gz"
41
+ ),
42
+ "space": "MNI152NLin6Asym",
43
+ },
34
44
  }
35
45
  dg1 = PatternDataladDataGrabber(
36
46
  rootdir=rootdir,
@@ -84,11 +94,21 @@ def test_MultipleDataGrabber_no_intersection() -> None:
84
94
  rootdir = "example_bids_ses"
85
95
  replacements = ["subject", "session"]
86
96
  pattern1 = {
87
- "T1w": "{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz",
97
+ "T1w": {
98
+ "pattern": (
99
+ "{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz"
100
+ ),
101
+ "space": "native",
102
+ },
88
103
  }
89
104
  pattern2 = {
90
- "BOLD": "{subject}/{session}/func/"
91
- "{subject}_{session}_task-rest_bold.nii.gz",
105
+ "BOLD": {
106
+ "pattern": (
107
+ "{subject}/{session}/func/"
108
+ "{subject}_{session}_task-rest_bold.nii.gz"
109
+ ),
110
+ "space": "MNI152NLin6Asym",
111
+ },
92
112
  }
93
113
  dg1 = PatternDataladDataGrabber(
94
114
  rootdir=rootdir,
@@ -119,7 +139,12 @@ def test_MultipleDataGrabber_get_item() -> None:
119
139
  rootdir = "example_bids_ses"
120
140
  replacements = ["subject", "session"]
121
141
  pattern1 = {
122
- "T1w": "{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz",
142
+ "T1w": {
143
+ "pattern": (
144
+ "{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz"
145
+ ),
146
+ "space": "native",
147
+ },
123
148
  }
124
149
  dg1 = PatternDataladDataGrabber(
125
150
  rootdir=rootdir,
@@ -142,10 +167,18 @@ def test_MultipleDataGrabber_validation() -> None:
142
167
  replacement1 = ["subject", "session"]
143
168
  replacement2 = ["subject"]
144
169
  pattern1 = {
145
- "T1w": "{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz",
170
+ "T1w": {
171
+ "pattern": (
172
+ "{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz"
173
+ ),
174
+ "space": "native",
175
+ },
146
176
  }
147
177
  pattern2 = {
148
- "bold": "{subject}/func/{subject}_task-rest_bold.nii.gz",
178
+ "BOLD": {
179
+ "pattern": "{subject}/func/{subject}_task-rest_bold.nii.gz",
180
+ "space": "MNI152NLin6Asym",
181
+ },
149
182
  }
150
183
  dg1 = PatternDataladDataGrabber(
151
184
  rootdir=rootdir,
@@ -158,7 +191,7 @@ def test_MultipleDataGrabber_validation() -> None:
158
191
  dg2 = PatternDataladDataGrabber(
159
192
  rootdir=rootdir,
160
193
  uri=repo_uri2,
161
- types=["bold"],
194
+ types=["BOLD"],
162
195
  patterns=pattern2,
163
196
  replacements=replacement2,
164
197
  )