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
@@ -1,388 +0,0 @@
1
- """Provide mixin validation class for pattern-based DataGrabber."""
2
-
3
- # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
- # License: AGPL
5
-
6
- from typing import Dict, List
7
-
8
- from ..utils import logger, raise_error, warn_with_log
9
-
10
-
11
- __all__ = ["PatternValidationMixin"]
12
-
13
-
14
- # Define schema for pattern-based datagrabber's patterns
15
- PATTERNS_SCHEMA = {
16
- "T1w": {
17
- "mandatory": ["pattern", "space"],
18
- "optional": {
19
- "mask": {"mandatory": ["pattern", "space"], "optional": []},
20
- },
21
- },
22
- "T2w": {
23
- "mandatory": ["pattern", "space"],
24
- "optional": {
25
- "mask": {"mandatory": ["pattern", "space"], "optional": []},
26
- },
27
- },
28
- "BOLD": {
29
- "mandatory": ["pattern", "space"],
30
- "optional": {
31
- "mask": {"mandatory": ["pattern", "space"], "optional": []},
32
- "confounds": {
33
- "mandatory": ["pattern", "format"],
34
- "optional": ["mappings"],
35
- },
36
- },
37
- },
38
- "Warp": {
39
- "mandatory": ["pattern", "src", "dst"],
40
- "optional": {},
41
- },
42
- "VBM_GM": {
43
- "mandatory": ["pattern", "space"],
44
- "optional": {},
45
- },
46
- "VBM_WM": {
47
- "mandatory": ["pattern", "space"],
48
- "optional": {},
49
- },
50
- "VBM_CSF": {
51
- "mandatory": ["pattern", "space"],
52
- "optional": {},
53
- },
54
- "DWI": {
55
- "mandatory": ["pattern"],
56
- "optional": {},
57
- },
58
- "FreeSurfer": {
59
- "mandatory": ["pattern"],
60
- "optional": {
61
- "aseg": {"mandatory": ["pattern"], "optional": []},
62
- "norm": {"mandatory": ["pattern"], "optional": []},
63
- "lh_white": {"mandatory": ["pattern"], "optional": []},
64
- "rh_white": {"mandatory": ["pattern"], "optional": []},
65
- "lh_pial": {"mandatory": ["pattern"], "optional": []},
66
- "rh_pial": {"mandatory": ["pattern"], "optional": []},
67
- },
68
- },
69
- }
70
-
71
-
72
- class PatternValidationMixin:
73
- """Mixin class for pattern validation."""
74
-
75
- def _validate_types(self, types: List[str]) -> None:
76
- """Validate the types.
77
-
78
- Parameters
79
- ----------
80
- types : list of str
81
- The data types to validate.
82
-
83
- Raises
84
- ------
85
- TypeError
86
- If ``types`` is not a list or if the values are not string.
87
-
88
- """
89
- if not isinstance(types, list):
90
- raise_error(msg="`types` must be a list", klass=TypeError)
91
- if any(not isinstance(x, str) for x in types):
92
- raise_error(
93
- msg="`types` must be a list of strings", klass=TypeError
94
- )
95
-
96
- def _validate_replacements(
97
- self,
98
- replacements: List[str],
99
- patterns: Dict[str, Dict[str, str]],
100
- partial_pattern_ok: bool,
101
- ) -> None:
102
- """Validate the replacements.
103
-
104
- Parameters
105
- ----------
106
- replacements : list of str
107
- The replacements to validate.
108
- patterns : dict
109
- The patterns to validate replacements against.
110
- partial_pattern_ok : bool
111
- Whether to raise error if partial pattern for a data type is found.
112
-
113
- Raises
114
- ------
115
- TypeError
116
- If ``replacements`` is not a list or if the values are not string.
117
- ValueError
118
- If a value in ``replacements`` is not part of a data type pattern
119
- and ``partial_pattern_ok=False`` or
120
- if no data type patterns contain all values in ``replacements`` and
121
- ``partial_pattern_ok=False``.
122
-
123
- Warns
124
- -----
125
- RuntimeWarning
126
- If a value in ``replacements`` is not part of the data type pattern
127
- and ``partial_pattern_ok=True``.
128
-
129
- """
130
- if not isinstance(replacements, list):
131
- raise_error(msg="`replacements` must be a list.", klass=TypeError)
132
-
133
- if any(not isinstance(x, str) for x in replacements):
134
- raise_error(
135
- msg="`replacements` must be a list of strings.",
136
- klass=TypeError,
137
- )
138
-
139
- for x in replacements:
140
- if all(
141
- x not in y
142
- for y in [
143
- data_type_val.get("pattern", "")
144
- for data_type_val in patterns.values()
145
- ]
146
- ):
147
- if partial_pattern_ok:
148
- warn_with_log(
149
- f"Replacement: `{x}` is not part of any pattern, "
150
- "things might not work as expected if you are unsure "
151
- "of what you are doing"
152
- )
153
- else:
154
- raise_error(
155
- msg=f"Replacement: {x} is not part of any pattern."
156
- )
157
-
158
- # Check that at least one pattern has all the replacements
159
- at_least_one = False
160
- for data_type_val in patterns.values():
161
- if all(
162
- x in data_type_val.get("pattern", "") for x in replacements
163
- ):
164
- at_least_one = True
165
- if not at_least_one and not partial_pattern_ok:
166
- raise_error(
167
- msg="At least one pattern must contain all replacements."
168
- )
169
-
170
- def _validate_mandatory_keys(
171
- self,
172
- keys: List[str],
173
- schema: List[str],
174
- data_type: str,
175
- partial_pattern_ok: bool = False,
176
- ) -> None:
177
- """Validate mandatory keys.
178
-
179
- Parameters
180
- ----------
181
- keys : list of str
182
- The keys to validate.
183
- schema : list of str
184
- The schema to validate against.
185
- data_type : str
186
- The data type being validated.
187
- partial_pattern_ok : bool, optional
188
- Whether to raise error if partial pattern for a data type is found
189
- (default True).
190
-
191
- Raises
192
- ------
193
- KeyError
194
- If any mandatory key is missing for a data type and
195
- ``partial_pattern_ok=False``.
196
-
197
- Warns
198
- -----
199
- RuntimeWarning
200
- If any mandatory key is missing for a data type and
201
- ``partial_pattern_ok=True``.
202
-
203
- """
204
- for key in schema:
205
- if key not in keys:
206
- if partial_pattern_ok:
207
- warn_with_log(
208
- f"Mandatory key: `{key}` not found for {data_type}, "
209
- "things might not work as expected if you are unsure "
210
- "of what you are doing"
211
- )
212
- else:
213
- raise_error(
214
- msg=f"Mandatory key: `{key}` missing for {data_type}",
215
- klass=KeyError,
216
- )
217
- else:
218
- logger.debug(f"Mandatory key: `{key}` found for {data_type}")
219
-
220
- def _identify_stray_keys(
221
- self, keys: List[str], schema: List[str], data_type: str
222
- ) -> None:
223
- """Identify stray keys.
224
-
225
- Parameters
226
- ----------
227
- keys : list of str
228
- The keys to check.
229
- schema : list of str
230
- The schema to check against.
231
- data_type : str
232
- The data type being checked.
233
-
234
- Raises
235
- ------
236
- RuntimeError
237
- If an unknown key is found for a data type.
238
-
239
- """
240
- for key in keys:
241
- if key not in schema:
242
- raise_error(
243
- msg=(
244
- f"Key: {key} not accepted for {data_type} "
245
- "pattern, remove it to proceed"
246
- ),
247
- klass=RuntimeError,
248
- )
249
-
250
- def validate_patterns(
251
- self,
252
- types: List[str],
253
- replacements: List[str],
254
- patterns: Dict[str, Dict[str, str]],
255
- partial_pattern_ok: bool = False,
256
- ) -> None:
257
- """Validate the patterns.
258
-
259
- Parameters
260
- ----------
261
- types : list of str
262
- The data types to check patterns of.
263
- replacements : list of str
264
- The replacements to be replaced in the patterns.
265
- patterns : dict
266
- The patterns to validate.
267
- partial_pattern_ok : bool, optional
268
- Whether to raise error if partial pattern for a data type is found.
269
- If False, a warning is issued instead of raising an error
270
- (default False).
271
-
272
- Raises
273
- ------
274
- TypeError
275
- If ``patterns`` is not a dictionary.
276
- ValueError
277
- If length of ``types`` and ``patterns`` are different or
278
- if ``patterns`` is missing entries from ``types`` or
279
- if unknown data type is found in ``patterns`` or
280
- if data type pattern key contains '*' as value.
281
-
282
- """
283
- # Validate types
284
- self._validate_types(types=types)
285
-
286
- # Validate patterns
287
- if not isinstance(patterns, dict):
288
- raise_error(msg="`patterns` must be a dict", klass=TypeError)
289
- # Unequal length of objects
290
- if len(types) > len(patterns):
291
- raise_error(
292
- msg="Length of `types` more than that of `patterns`",
293
- klass=ValueError,
294
- )
295
- # Missing type in patterns
296
- if any(x not in patterns for x in types):
297
- raise_error(
298
- msg="`patterns` must contain all `types`", klass=ValueError
299
- )
300
- # Check against schema
301
- for data_type_key, data_type_val in patterns.items():
302
- # Check if valid data type is provided
303
- if data_type_key not in PATTERNS_SCHEMA:
304
- raise_error(
305
- f"Unknown data type: {data_type_key}, "
306
- f"should be one of: {list(PATTERNS_SCHEMA.keys())}"
307
- )
308
- # Check mandatory keys for data type
309
- self._validate_mandatory_keys(
310
- keys=list(data_type_val),
311
- schema=PATTERNS_SCHEMA[data_type_key]["mandatory"],
312
- data_type=data_type_key,
313
- partial_pattern_ok=partial_pattern_ok,
314
- )
315
- # Check optional keys for data type
316
- for optional_key, optional_val in PATTERNS_SCHEMA[data_type_key][
317
- "optional"
318
- ].items():
319
- if optional_key not in data_type_val:
320
- logger.debug(
321
- f"Optional key: `{optional_key}` missing for "
322
- f"{data_type_key}"
323
- )
324
- else:
325
- logger.debug(
326
- f"Optional key: `{optional_key}` found for "
327
- f"{data_type_key}"
328
- )
329
- # Set nested type name for easier access
330
- nested_data_type = f"{data_type_key}.{optional_key}"
331
- nested_mandatory_keys_schema = PATTERNS_SCHEMA[
332
- data_type_key
333
- ]["optional"][optional_key]["mandatory"]
334
- nested_optional_keys_schema = PATTERNS_SCHEMA[
335
- data_type_key
336
- ]["optional"][optional_key]["optional"]
337
- # Check mandatory keys for nested type
338
- self._validate_mandatory_keys(
339
- keys=list(optional_val["mandatory"]),
340
- schema=nested_mandatory_keys_schema,
341
- data_type=nested_data_type,
342
- partial_pattern_ok=partial_pattern_ok,
343
- )
344
- # Check optional keys for nested type
345
- for nested_optional_key in nested_optional_keys_schema:
346
- if nested_optional_key not in optional_val["optional"]:
347
- logger.debug(
348
- f"Optional key: `{nested_optional_key}` "
349
- f"missing for {nested_data_type}"
350
- )
351
- else:
352
- logger.debug(
353
- f"Optional key: `{nested_optional_key}` found "
354
- f"for {nested_data_type}"
355
- )
356
- # Check stray key for nested data type
357
- self._identify_stray_keys(
358
- keys=optional_val["mandatory"]
359
- + optional_val["optional"],
360
- schema=nested_mandatory_keys_schema
361
- + nested_optional_keys_schema,
362
- data_type=nested_data_type,
363
- )
364
- # Check stray key for data type
365
- self._identify_stray_keys(
366
- keys=list(data_type_val.keys()),
367
- schema=(
368
- PATTERNS_SCHEMA[data_type_key]["mandatory"]
369
- + list(PATTERNS_SCHEMA[data_type_key]["optional"].keys())
370
- ),
371
- data_type=data_type_key,
372
- )
373
- # Wildcard check in patterns
374
- if "}*" in data_type_val.get("pattern", ""):
375
- raise_error(
376
- msg=(
377
- f"`{data_type_key}.pattern` must not contain `*` "
378
- "following a replacement"
379
- ),
380
- klass=ValueError,
381
- )
382
-
383
- # Validate replacements
384
- self._validate_replacements(
385
- replacements=replacements,
386
- patterns=patterns,
387
- partial_pattern_ok=partial_pattern_ok,
388
- )
@@ -1,249 +0,0 @@
1
- """Provide tests for PatternValidationMixin."""
2
-
3
- # Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
4
- # Synchon Mandal <s.mandal@fz-juelich.de>
5
- # License: AGPL
6
-
7
- from contextlib import nullcontext
8
- from typing import ContextManager, Dict, List, Union
9
-
10
- import pytest
11
-
12
- from junifer.datagrabber.pattern_validation_mixin import PatternValidationMixin
13
-
14
-
15
- @pytest.mark.parametrize(
16
- "types, replacements, patterns, expect",
17
- [
18
- (
19
- "wrong",
20
- [],
21
- {},
22
- pytest.raises(TypeError, match="`types` must be a list"),
23
- ),
24
- (
25
- [1],
26
- [],
27
- {},
28
- pytest.raises(
29
- TypeError, match="`types` must be a list of strings"
30
- ),
31
- ),
32
- (
33
- ["BOLD"],
34
- [],
35
- "wrong",
36
- pytest.raises(TypeError, match="`patterns` must be a dict"),
37
- ),
38
- (
39
- ["T1w", "BOLD"],
40
- "",
41
- {
42
- "T1w": {"pattern": "{subject}/anat/{subject}_T1w.nii.gz"},
43
- },
44
- pytest.raises(
45
- ValueError,
46
- match="Length of `types` more than that of `patterns`",
47
- ),
48
- ),
49
- (
50
- ["T1w", "BOLD"],
51
- "",
52
- {
53
- "T1w": {"pattern": "{subject}/anat/{subject}_T1w.nii.gz"},
54
- "T2w": {"pattern": "{subject}/anat/{subject}_T2w.nii.gz"},
55
- },
56
- pytest.raises(
57
- ValueError, match="`patterns` must contain all `types`"
58
- ),
59
- ),
60
- (
61
- ["T3w"],
62
- "",
63
- {
64
- "T3w": {"pattern": "{subject}/anat/{subject}_T3w.nii.gz"},
65
- },
66
- pytest.raises(ValueError, match="Unknown data type"),
67
- ),
68
- (
69
- ["BOLD"],
70
- "",
71
- {
72
- "BOLD": {"patterns": "{subject}/func/{subject}_BOLD.nii.gz"},
73
- },
74
- pytest.raises(KeyError, match="Mandatory key"),
75
- ),
76
- (
77
- ["BOLD"],
78
- "",
79
- {
80
- "BOLD": {
81
- "pattern": (
82
- "{subject}/func/{subject}_task-rest_bold.nii.gz"
83
- ),
84
- "space": "MNINLin6Asym",
85
- "confounds": {
86
- "pattern": "{subject}/func/{subject}_confounds.tsv",
87
- "format": "fmriprep",
88
- },
89
- "zip": "zap",
90
- },
91
- },
92
- pytest.raises(RuntimeError, match="not accepted"),
93
- ),
94
- (
95
- ["T1w"],
96
- "",
97
- {
98
- "T1w": {
99
- "pattern": "{subject}/anat/{subject}*.nii",
100
- "space": "native",
101
- },
102
- },
103
- pytest.raises(ValueError, match="following a replacement"),
104
- ),
105
- (
106
- ["T1w"],
107
- "wrong",
108
- {
109
- "T1w": {
110
- "pattern": "{subject}/anat/{subject}_T1w.nii",
111
- "space": "native",
112
- },
113
- },
114
- pytest.raises(TypeError, match="`replacements` must be a list"),
115
- ),
116
- (
117
- ["T1w"],
118
- [1],
119
- {
120
- "T1w": {
121
- "pattern": "{subject}/anat/{subject}_T1w.nii",
122
- "space": "native",
123
- },
124
- },
125
- pytest.raises(
126
- TypeError, match="`replacements` must be a list of strings"
127
- ),
128
- ),
129
- (
130
- ["T1w", "BOLD"],
131
- ["subject", "session"],
132
- {
133
- "T1w": {
134
- "pattern": "{subject}/anat/{subject}_T1w.nii.gz",
135
- "space": "native",
136
- },
137
- "BOLD": {
138
- "pattern": (
139
- "{subject}/func/{subject}_task-rest_bold.nii.gz"
140
- ),
141
- "space": "MNI152NLin6Asym",
142
- },
143
- },
144
- pytest.raises(ValueError, match="is not part of any pattern"),
145
- ),
146
- (
147
- ["BOLD"],
148
- ["subject", "session"],
149
- {
150
- "T1w": {
151
- "pattern": "{subject}/anat/_T1w.nii.gz",
152
- "space": "native",
153
- },
154
- "BOLD": {
155
- "pattern": "{session}/func/_task-rest_bold.nii.gz",
156
- "space": "MNI152NLin6Asym",
157
- },
158
- },
159
- pytest.raises(ValueError, match="At least one pattern"),
160
- ),
161
- (
162
- ["T1w", "T2w", "BOLD"],
163
- ["subject"],
164
- {
165
- "T1w": {
166
- "pattern": "{subject}/anat/{subject}_T1w.nii.gz",
167
- "space": "native",
168
- },
169
- "T2w": {
170
- "pattern": "{subject}/anat/{subject}_T2w.nii.gz",
171
- "space": "native",
172
- },
173
- "BOLD": {
174
- "pattern": (
175
- "{subject}/func/{session}/{subject}_task-rest_bold.nii.gz"
176
- ),
177
- "space": "MNI152NLin6Asym",
178
- "confounds": {
179
- "pattern": "{subject}/func/{subject}_confounds.tsv",
180
- "format": "fmriprep",
181
- },
182
- },
183
- },
184
- nullcontext(),
185
- ),
186
- ],
187
- )
188
- def test_PatternValidationMixin(
189
- types: Union[str, List[str], List[int]],
190
- replacements: Union[str, List[str], List[int]],
191
- patterns: Union[str, Dict[str, Dict[str, str]]],
192
- expect: ContextManager,
193
- ) -> None:
194
- """Test validation.
195
-
196
- Parameters
197
- ----------
198
- types : str, list of int or str
199
- The parametrized data types to validate.
200
- replacements : str, list of str or int
201
- The parametrized pattern replacements to validate.
202
- patterns : str, dict
203
- The parametrized patterns to validate against.
204
- expect : typing.ContextManager
205
- The parametrized ContextManager object.
206
-
207
- """
208
-
209
- class MockDataGrabber(PatternValidationMixin):
210
- def __init__(
211
- self,
212
- types,
213
- replacements,
214
- patterns,
215
- ) -> None:
216
- self.types = types
217
- self.replacements = replacements
218
- self.patterns = patterns
219
-
220
- def validate(self) -> None:
221
- self.validate_patterns(
222
- types=self.types,
223
- replacements=self.replacements,
224
- patterns=self.patterns,
225
- )
226
-
227
- dg = MockDataGrabber(types, replacements, patterns)
228
- with expect:
229
- dg.validate()
230
-
231
-
232
- # This test is kept separate as bool doesn't support context manager protocol,
233
- # used in the earlier test
234
- def test_PatternValidationMixin_partial_pattern_check() -> None:
235
- """Test validation for partial patterns."""
236
- with pytest.warns(RuntimeWarning, match="might not work as expected"):
237
- PatternValidationMixin().validate_patterns(
238
- types=["BOLD"],
239
- replacements=["subject"],
240
- patterns={
241
- "BOLD": {
242
- "mask": {
243
- "pattern": "{subject}/func/{subject}_BOLD.nii.gz",
244
- "space": "MNI152NLin6Asym",
245
- },
246
- },
247
- }, # type: ignore
248
- partial_pattern_ok=True,
249
- )
@@ -1,4 +0,0 @@
1
- from ._version import __version__ # noqa: F401
2
- from .brainprint import compute_asymmetry, compute_brainprint # noqa: F401
3
- from .surfaces import surf_to_vtk # noqa: F401
4
- from .utils._config import sys_info # noqa: F401
@@ -1,3 +0,0 @@
1
- """Version number."""
2
-
3
- __version__ = "0.4.0"