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
@@ -7,15 +7,10 @@
7
7
 
8
8
  from typing import Dict, List, Tuple, Union
9
9
 
10
- from ..api.decorators import register_datagrabber
11
- from ..utils import deep_update, raise_error
10
+ from ..utils import raise_error
12
11
  from .base import BaseDataGrabber
13
12
 
14
13
 
15
- __all__ = ["MultipleDataGrabber"]
16
-
17
-
18
- @register_datagrabber
19
14
  class MultipleDataGrabber(BaseDataGrabber):
20
15
  """Concrete implementation for multi sourced data fetching.
21
16
 
@@ -29,53 +24,19 @@ class MultipleDataGrabber(BaseDataGrabber):
29
24
  **kwargs
30
25
  Keyword arguments passed to superclass.
31
26
 
32
- Raises
33
- ------
34
- RuntimeError
35
- If ``datagrabbers`` have different element keys or
36
- overlapping data types or nested data types.
37
-
38
27
  """
39
28
 
40
29
  def __init__(self, datagrabbers: List[BaseDataGrabber], **kwargs) -> None:
41
30
  # Check datagrabbers consistency
42
- # Check for same element keys
31
+ # 1) same element keys
43
32
  first_keys = datagrabbers[0].get_element_keys()
44
33
  for dg in datagrabbers[1:]:
45
34
  if dg.get_element_keys() != first_keys:
46
- raise_error(
47
- msg="DataGrabbers have different element keys",
48
- klass=RuntimeError,
49
- )
50
- # Check for no overlapping types (and nested data types)
35
+ raise_error("DataGrabbers have different element keys.")
36
+ # 2) no overlapping types
51
37
  types = [x for dg in datagrabbers for x in dg.get_types()]
52
38
  if len(types) != len(set(types)):
53
- if all(hasattr(dg, "patterns") for dg in datagrabbers):
54
- first_patterns = datagrabbers[0].patterns
55
- for dg in datagrabbers[1:]:
56
- for data_type in set(types):
57
- dtype_pattern = dg.patterns.get(data_type)
58
- if dtype_pattern is None:
59
- continue
60
- # Check if first-level keys of data type are same
61
- if (
62
- dtype_pattern.keys()
63
- == first_patterns[data_type].keys()
64
- ):
65
- raise_error(
66
- msg=(
67
- "DataGrabbers have overlapping mandatory "
68
- "and / or optional key(s) for data type: "
69
- f"`{data_type}`"
70
- ),
71
- klass=RuntimeError,
72
- )
73
- else:
74
- # Can't check further
75
- raise_error(
76
- msg="DataGrabbers have overlapping types",
77
- klass=RuntimeError,
78
- )
39
+ raise_error("DataGrabbers have overlapping types.")
79
40
  self._datagrabbers = datagrabbers
80
41
 
81
42
  def __getitem__(self, element: Union[str, Tuple]) -> Dict:
@@ -101,7 +62,7 @@ class MultipleDataGrabber(BaseDataGrabber):
101
62
  metas = []
102
63
  for dg in self._datagrabbers:
103
64
  t_out = dg[element]
104
- deep_update(out, t_out)
65
+ out.update(t_out)
105
66
  # Now get the meta for this datagrabber
106
67
  t_meta = {}
107
68
  dg.update_meta(t_meta, "datagrabber")
@@ -6,7 +6,6 @@
6
6
  # License: AGPL
7
7
 
8
8
  import re
9
- from copy import deepcopy
10
9
  from pathlib import Path
11
10
  from typing import Dict, List, Optional, Tuple, Union
12
11
 
@@ -15,10 +14,7 @@ import numpy as np
15
14
  from ..api.decorators import register_datagrabber
16
15
  from ..utils import logger, raise_error
17
16
  from .base import BaseDataGrabber
18
- from .pattern_validation_mixin import PatternValidationMixin
19
-
20
-
21
- __all__ = ["PatternDataGrabber"]
17
+ from .utils import validate_patterns, validate_replacements
22
18
 
23
19
 
24
20
  # Accepted formats for confounds specification
@@ -26,7 +22,7 @@ _CONFOUNDS_FORMATS = ("fmriprep", "adhoc")
26
22
 
27
23
 
28
24
  @register_datagrabber
29
- class PatternDataGrabber(BaseDataGrabber, PatternValidationMixin):
25
+ class PatternDataGrabber(BaseDataGrabber):
30
26
  """Concrete implementation for pattern-based data fetching.
31
27
 
32
28
  Implements a DataGrabber that understands patterns to grab data.
@@ -44,12 +40,7 @@ class PatternDataGrabber(BaseDataGrabber, PatternValidationMixin):
44
40
 
45
41
  {
46
42
  "mandatory": ["pattern", "space"],
47
- "optional": {
48
- "mask": {
49
- "mandatory": ["pattern", "space"],
50
- "optional": []
51
- }
52
- }
43
+ "optional": []
53
44
  }
54
45
 
55
46
  * ``"T2w"`` :
@@ -58,12 +49,7 @@ class PatternDataGrabber(BaseDataGrabber, PatternValidationMixin):
58
49
 
59
50
  {
60
51
  "mandatory": ["pattern", "space"],
61
- "optional": {
62
- "mask": {
63
- "mandatory": ["pattern", "space"],
64
- "optional": []
65
- }
66
- }
52
+ "optional": []
67
53
  }
68
54
 
69
55
  * ``"BOLD"`` :
@@ -72,16 +58,7 @@ class PatternDataGrabber(BaseDataGrabber, PatternValidationMixin):
72
58
 
73
59
  {
74
60
  "mandatory": ["pattern", "space"],
75
- "optional": {
76
- "mask": {
77
- "mandatory": ["pattern", "space"],
78
- "optional": []
79
- }
80
- "confounds": {
81
- "mandatory": ["pattern", "format"],
82
- "optional": []
83
- }
84
- }
61
+ "optional": ["mask_item"]
85
62
  }
86
63
 
87
64
  * ``"Warp"`` :
@@ -93,6 +70,15 @@ class PatternDataGrabber(BaseDataGrabber, PatternValidationMixin):
93
70
  "optional": []
94
71
  }
95
72
 
73
+ * ``"BOLD_confounds"`` :
74
+
75
+ .. code-block:: none
76
+
77
+ {
78
+ "mandatory": ["pattern", "format"],
79
+ "optional": []
80
+ }
81
+
96
82
  * ``"VBM_GM"`` :
97
83
 
98
84
  .. code-block:: none
@@ -142,13 +128,6 @@ class PatternDataGrabber(BaseDataGrabber, PatternValidationMixin):
142
128
  The directory where the data is / will be stored.
143
129
  confounds_format : {"fmriprep", "adhoc"} or None, optional
144
130
  The format of the confounds for the dataset (default None).
145
- partial_pattern_ok : bool, optional
146
- Whether to raise error if partial pattern for a data type is found.
147
- This allows to bypass mandatory key check and issue a warning
148
- instead of raising error. This allows one to have a DataGrabber
149
- with data types without the corresponding mandatory keys and is
150
- powerful when used with :class:`.MultipleDataGrabber`
151
- (default True).
152
131
 
153
132
  Raises
154
133
  ------
@@ -164,21 +143,17 @@ class PatternDataGrabber(BaseDataGrabber, PatternValidationMixin):
164
143
  replacements: Union[List[str], str],
165
144
  datadir: Union[str, Path],
166
145
  confounds_format: Optional[str] = None,
167
- partial_pattern_ok: bool = False,
168
146
  ) -> None:
147
+ # Validate patterns
148
+ validate_patterns(types=types, patterns=patterns)
149
+ self.patterns = patterns
150
+
169
151
  # Convert replacements to list if not already
170
152
  if not isinstance(replacements, list):
171
153
  replacements = [replacements]
172
- # Validate patterns
173
- self.validate_patterns(
174
- types=types,
175
- replacements=replacements,
176
- patterns=patterns,
177
- partial_pattern_ok=partial_pattern_ok,
178
- )
154
+ # Validate replacements
155
+ validate_replacements(replacements=replacements, patterns=patterns)
179
156
  self.replacements = replacements
180
- self.patterns = patterns
181
- self.partial_pattern_ok = partial_pattern_ok
182
157
 
183
158
  # Validate confounds format
184
159
  if (
@@ -229,25 +204,18 @@ class PatternDataGrabber(BaseDataGrabber, PatternValidationMixin):
229
204
  t_replacements = [
230
205
  x for x in self.replacements if f"{{{x}}}" in pattern
231
206
  ]
232
- # Ops on re_pattern
233
- # Remove negated unix glob pattern i.e., [!...] for re_pattern
234
- re_pattern = re.sub(r"\[!.?\]", "", re_pattern)
235
- # Remove enclosing square brackets from unix glob pattern i.e., [...]
236
- # for re_pattern
237
- re_pattern = re.sub(r"\[|\]", "", re_pattern)
238
- # Iteratively replace the first of each with a named group definition
207
+
239
208
  for t_r in t_replacements:
209
+ # Replace the first of each with a named group definition
240
210
  re_pattern = re_pattern.replace(f"{{{t_r}}}", f"(?P<{t_r}>.*)", 1)
241
- # Iteratively replace the second appearance of each with the named
242
- # group back reference
211
+
243
212
  for t_r in t_replacements:
213
+ # Replace the second appearance of each with the named group
214
+ # back reference
244
215
  re_pattern = re_pattern.replace(f"{{{t_r}}}", f"(?P={t_r})")
245
- # Ops on glob_pattern
246
- # Iteratively replace replacements with wildcard i.e., *
247
- # for glob_pattern
216
+
248
217
  for t_r in t_replacements:
249
218
  glob_pattern = glob_pattern.replace(f"{{{t_r}}}", "*")
250
-
251
219
  return re_pattern, glob_pattern, t_replacements
252
220
 
253
221
  def _replace_patterns_glob(self, element: Dict, pattern: str) -> str:
@@ -276,70 +244,8 @@ class PatternDataGrabber(BaseDataGrabber, PatternValidationMixin):
276
244
  f"The element keys must be {self.replacements}, "
277
245
  f"element has {list(element.keys())}."
278
246
  )
279
- # Remove negated unix glob pattern i.e., [!...]
280
- pattern = re.sub(r"\[!.?\]", "", pattern)
281
- # Remove enclosing square brackets from unix glob pattern i.e., [...]
282
- pattern = re.sub(r"\[|\]", "", pattern)
283
247
  return pattern.format(**element)
284
248
 
285
- def _get_path_from_patterns(
286
- self, element: Dict, pattern: str, data_type: str
287
- ) -> Path:
288
- """Get path from resolved patterns.
289
-
290
- Parameters
291
- ----------
292
- element : dict
293
- The element to be used in the replacement.
294
- pattern : str
295
- The pattern to be replaced.
296
- data_type : str
297
- The data type of the pattern.
298
-
299
- Returns
300
- -------
301
- pathlib.Path
302
- The path for the resolved pattern.
303
-
304
- Raises
305
- ------
306
- RuntimeError
307
- If more than one file matches for a data type's pattern or
308
- if no file matches for a data type's pattern or
309
- if file cannot be accessed for an element.
310
-
311
- """
312
- # Replace element in the pattern for globbing
313
- resolved_pattern = self._replace_patterns_glob(element, pattern)
314
- # Resolve path for wildcard
315
- if "*" in resolved_pattern:
316
- t_matches = list(self.datadir.absolute().glob(resolved_pattern))
317
- # Multiple matches
318
- if len(t_matches) > 1:
319
- raise_error(
320
- f"More than one file matches for {element} / {data_type}:"
321
- f" {t_matches}",
322
- klass=RuntimeError,
323
- )
324
- # No matches
325
- elif len(t_matches) == 0:
326
- raise_error(
327
- f"No file matches for {element} / {data_type}",
328
- klass=RuntimeError,
329
- )
330
- path = t_matches[0]
331
- else:
332
- path = self.datadir / resolved_pattern
333
- if not self.skip_file_check:
334
- if not path.exists() and not path.is_symlink():
335
- raise_error(
336
- f"Cannot access {data_type} for {element}: "
337
- f"File {path} does not exist",
338
- klass=RuntimeError,
339
- )
340
-
341
- return path
342
-
343
249
  def get_element_keys(self) -> List[str]:
344
250
  """Get element keys.
345
251
 
@@ -373,49 +279,47 @@ class PatternDataGrabber(BaseDataGrabber, PatternValidationMixin):
373
279
  Dictionary of dictionaries for each type of data required for the
374
280
  specified element.
375
281
 
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
+
376
289
  """
377
290
  out = {}
378
291
  for t_type in self.types:
379
- # Data type dictionary
380
292
  t_pattern = self.patterns[t_type]
381
- # Copy data type dictionary in output
382
- out[t_type] = deepcopy(t_pattern)
383
- # Iterate to check for nested "types" like mask
384
- for k, v in t_pattern.items():
385
- # Resolve pattern for base data type
386
- if k == "pattern":
387
- logger.info(f"Resolving path from pattern for {t_type}")
388
- # Resolve pattern
389
- base_data_type_pattern_path = self._get_path_from_patterns(
390
- element=element,
391
- pattern=v,
392
- data_type=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,
393
303
  )
394
- # Remove pattern key
395
- out[t_type].pop("pattern")
396
- # Add path key
397
- out[t_type].update({"path": base_data_type_pattern_path})
398
- # Resolve pattern for nested data type
399
- if isinstance(v, dict) and "pattern" in v:
400
- # Set nested type key for easier access
401
- t_nested_type = f"{t_type}.{k}"
402
- logger.info(
403
- f"Resolving path from pattern for {t_nested_type}"
304
+ elif len(t_matches) == 0:
305
+ raise_error(
306
+ f"No file matches for {element} / {t_type}",
307
+ klass=RuntimeError,
404
308
  )
405
- # Resolve pattern
406
- nested_data_type_pattern_path = (
407
- self._get_path_from_patterns(
408
- element=element,
409
- pattern=v["pattern"],
410
- data_type=t_nested_type,
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,
411
318
  )
412
- )
413
- # Remove pattern key
414
- out[t_type][k].pop("pattern")
415
- # Add path key
416
- out[t_type][k].update(
417
- {"path": nested_data_type_pattern_path}
418
- )
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
419
323
 
420
324
  return out
421
325
 
@@ -447,26 +351,14 @@ class PatternDataGrabber(BaseDataGrabber, PatternValidationMixin):
447
351
  for t_idx in reversed(order):
448
352
  t_type = self.types[t_idx]
449
353
  types_element = set()
450
-
451
- # Get the pattern dict
354
+ # Get the pattern
452
355
  t_pattern = self.patterns[t_type]
453
- # Conditional fetch of base pattern for getting elements
454
- pattern = None
455
- # Try for data type pattern
456
- pattern = t_pattern.get("pattern")
457
- # Try for nested data type pattern
458
- if pattern is None and self.partial_pattern_ok:
459
- for v in t_pattern.values():
460
- if isinstance(v, dict) and "pattern" in v:
461
- pattern = v["pattern"]
462
- break
463
-
464
356
  # Replace the pattern
465
357
  (
466
358
  re_pattern,
467
359
  glob_pattern,
468
360
  t_replacements,
469
- ) = self._replace_patterns_regex(pattern)
361
+ ) = self._replace_patterns_regex(t_pattern["pattern"])
470
362
  for fname in self.datadir.glob(glob_pattern):
471
363
  suffix = fname.relative_to(self.datadir).as_posix()
472
364
  m = re.match(re_pattern, suffix)
@@ -12,9 +12,6 @@ from .datalad_base import DataladDataGrabber
12
12
  from .pattern import PatternDataGrabber
13
13
 
14
14
 
15
- __all__ = ["PatternDataladDataGrabber"]
16
-
17
-
18
15
  @register_datagrabber
19
16
  class PatternDataladDataGrabber(DataladDataGrabber, PatternDataGrabber):
20
17
  """Concrete implementation for pattern and datalad based data fetching.
@@ -35,12 +32,7 @@ class PatternDataladDataGrabber(DataladDataGrabber, PatternDataGrabber):
35
32
 
36
33
  {
37
34
  "mandatory": ["pattern", "space"],
38
- "optional": {
39
- "mask": {
40
- "mandatory": ["pattern", "space"],
41
- "optional": []
42
- }
43
- }
35
+ "optional": []
44
36
  }
45
37
 
46
38
  * ``"T2w"`` :
@@ -49,12 +41,7 @@ class PatternDataladDataGrabber(DataladDataGrabber, PatternDataGrabber):
49
41
 
50
42
  {
51
43
  "mandatory": ["pattern", "space"],
52
- "optional": {
53
- "mask": {
54
- "mandatory": ["pattern", "space"],
55
- "optional": []
56
- }
57
- }
44
+ "optional": []
58
45
  }
59
46
 
60
47
  * ``"BOLD"`` :
@@ -63,16 +50,7 @@ class PatternDataladDataGrabber(DataladDataGrabber, PatternDataGrabber):
63
50
 
64
51
  {
65
52
  "mandatory": ["pattern", "space"],
66
- "optional": {
67
- "mask": {
68
- "mandatory": ["pattern", "space"],
69
- "optional": []
70
- }
71
- "confounds": {
72
- "mandatory": ["pattern", "format"],
73
- "optional": []
74
- }
75
- }
53
+ "optional": ["mask_item"]
76
54
  }
77
55
 
78
56
  * ``"Warp"`` :
@@ -84,6 +62,15 @@ class PatternDataladDataGrabber(DataladDataGrabber, PatternDataGrabber):
84
62
  "optional": []
85
63
  }
86
64
 
65
+ * ``"BOLD_confounds"`` :
66
+
67
+ .. code-block:: none
68
+
69
+ {
70
+ "mandatory": ["pattern", "format"],
71
+ "optional": []
72
+ }
73
+
87
74
  * ``"VBM_GM"`` :
88
75
 
89
76
  .. code-block:: none