junifer 0.0.5.dev240__py3-none-any.whl → 0.0.6__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 (279) hide show
  1. junifer/__init__.py +2 -31
  2. junifer/__init__.pyi +37 -0
  3. junifer/_version.py +9 -4
  4. junifer/api/__init__.py +3 -5
  5. junifer/api/__init__.pyi +4 -0
  6. junifer/api/decorators.py +14 -19
  7. junifer/api/functions.py +165 -109
  8. junifer/api/py.typed +0 -0
  9. junifer/api/queue_context/__init__.py +2 -4
  10. junifer/api/queue_context/__init__.pyi +5 -0
  11. junifer/api/queue_context/gnu_parallel_local_adapter.py +22 -6
  12. junifer/api/queue_context/htcondor_adapter.py +23 -6
  13. junifer/api/queue_context/py.typed +0 -0
  14. junifer/api/queue_context/tests/test_gnu_parallel_local_adapter.py +3 -3
  15. junifer/api/queue_context/tests/test_htcondor_adapter.py +3 -3
  16. junifer/api/tests/test_functions.py +168 -74
  17. junifer/cli/__init__.py +24 -0
  18. junifer/cli/__init__.pyi +3 -0
  19. junifer/{api → cli}/cli.py +141 -125
  20. junifer/cli/parser.py +235 -0
  21. junifer/cli/py.typed +0 -0
  22. junifer/{api → cli}/tests/test_cli.py +8 -8
  23. junifer/{api/tests/test_api_utils.py → cli/tests/test_cli_utils.py} +5 -4
  24. junifer/{api → cli}/tests/test_parser.py +2 -2
  25. junifer/{api → cli}/utils.py +6 -16
  26. junifer/configs/juseless/__init__.py +2 -2
  27. junifer/configs/juseless/__init__.pyi +3 -0
  28. junifer/configs/juseless/datagrabbers/__init__.py +2 -12
  29. junifer/configs/juseless/datagrabbers/__init__.pyi +13 -0
  30. junifer/configs/juseless/datagrabbers/ixi_vbm.py +2 -2
  31. junifer/configs/juseless/datagrabbers/py.typed +0 -0
  32. junifer/configs/juseless/datagrabbers/tests/test_ucla.py +2 -2
  33. junifer/configs/juseless/datagrabbers/ucla.py +4 -4
  34. junifer/configs/juseless/py.typed +0 -0
  35. junifer/conftest.py +25 -0
  36. junifer/data/__init__.py +2 -42
  37. junifer/data/__init__.pyi +29 -0
  38. junifer/data/_dispatch.py +248 -0
  39. junifer/data/coordinates/__init__.py +9 -0
  40. junifer/data/coordinates/__init__.pyi +5 -0
  41. junifer/data/coordinates/_ants_coordinates_warper.py +104 -0
  42. junifer/data/coordinates/_coordinates.py +385 -0
  43. junifer/data/coordinates/_fsl_coordinates_warper.py +81 -0
  44. junifer/data/{tests → coordinates/tests}/test_coordinates.py +26 -33
  45. junifer/data/masks/__init__.py +9 -0
  46. junifer/data/masks/__init__.pyi +6 -0
  47. junifer/data/masks/_ants_mask_warper.py +177 -0
  48. junifer/data/masks/_fsl_mask_warper.py +106 -0
  49. junifer/data/masks/_masks.py +802 -0
  50. junifer/data/{tests → masks/tests}/test_masks.py +67 -63
  51. junifer/data/parcellations/__init__.py +9 -0
  52. junifer/data/parcellations/__init__.pyi +6 -0
  53. junifer/data/parcellations/_ants_parcellation_warper.py +166 -0
  54. junifer/data/parcellations/_fsl_parcellation_warper.py +89 -0
  55. junifer/data/parcellations/_parcellations.py +1388 -0
  56. junifer/data/{tests → parcellations/tests}/test_parcellations.py +165 -295
  57. junifer/data/pipeline_data_registry_base.py +76 -0
  58. junifer/data/py.typed +0 -0
  59. junifer/data/template_spaces.py +44 -79
  60. junifer/data/tests/test_data_utils.py +1 -2
  61. junifer/data/tests/test_template_spaces.py +8 -4
  62. junifer/data/utils.py +109 -4
  63. junifer/datagrabber/__init__.py +2 -26
  64. junifer/datagrabber/__init__.pyi +27 -0
  65. junifer/datagrabber/aomic/__init__.py +2 -4
  66. junifer/datagrabber/aomic/__init__.pyi +5 -0
  67. junifer/datagrabber/aomic/id1000.py +81 -52
  68. junifer/datagrabber/aomic/piop1.py +83 -55
  69. junifer/datagrabber/aomic/piop2.py +85 -56
  70. junifer/datagrabber/aomic/py.typed +0 -0
  71. junifer/datagrabber/aomic/tests/test_id1000.py +19 -12
  72. junifer/datagrabber/aomic/tests/test_piop1.py +52 -18
  73. junifer/datagrabber/aomic/tests/test_piop2.py +50 -17
  74. junifer/datagrabber/base.py +22 -18
  75. junifer/datagrabber/datalad_base.py +71 -34
  76. junifer/datagrabber/dmcc13_benchmark.py +31 -18
  77. junifer/datagrabber/hcp1200/__init__.py +2 -3
  78. junifer/datagrabber/hcp1200/__init__.pyi +4 -0
  79. junifer/datagrabber/hcp1200/datalad_hcp1200.py +3 -3
  80. junifer/datagrabber/hcp1200/hcp1200.py +26 -15
  81. junifer/datagrabber/hcp1200/py.typed +0 -0
  82. junifer/datagrabber/hcp1200/tests/test_hcp1200.py +8 -2
  83. junifer/datagrabber/multiple.py +14 -9
  84. junifer/datagrabber/pattern.py +132 -96
  85. junifer/datagrabber/pattern_validation_mixin.py +206 -94
  86. junifer/datagrabber/py.typed +0 -0
  87. junifer/datagrabber/tests/test_datalad_base.py +27 -12
  88. junifer/datagrabber/tests/test_dmcc13_benchmark.py +28 -11
  89. junifer/datagrabber/tests/test_multiple.py +48 -2
  90. junifer/datagrabber/tests/test_pattern_datalad.py +1 -1
  91. junifer/datagrabber/tests/test_pattern_validation_mixin.py +6 -6
  92. junifer/datareader/__init__.py +2 -2
  93. junifer/datareader/__init__.pyi +3 -0
  94. junifer/datareader/default.py +6 -6
  95. junifer/datareader/py.typed +0 -0
  96. junifer/external/nilearn/__init__.py +2 -3
  97. junifer/external/nilearn/__init__.pyi +4 -0
  98. junifer/external/nilearn/junifer_connectivity_measure.py +25 -17
  99. junifer/external/nilearn/junifer_nifti_spheres_masker.py +4 -4
  100. junifer/external/nilearn/py.typed +0 -0
  101. junifer/external/nilearn/tests/test_junifer_connectivity_measure.py +17 -16
  102. junifer/external/nilearn/tests/test_junifer_nifti_spheres_masker.py +2 -3
  103. junifer/markers/__init__.py +2 -38
  104. junifer/markers/__init__.pyi +37 -0
  105. junifer/markers/base.py +11 -14
  106. junifer/markers/brainprint.py +12 -14
  107. junifer/markers/complexity/__init__.py +2 -18
  108. junifer/markers/complexity/__init__.pyi +17 -0
  109. junifer/markers/complexity/complexity_base.py +9 -11
  110. junifer/markers/complexity/hurst_exponent.py +7 -7
  111. junifer/markers/complexity/multiscale_entropy_auc.py +7 -7
  112. junifer/markers/complexity/perm_entropy.py +7 -7
  113. junifer/markers/complexity/py.typed +0 -0
  114. junifer/markers/complexity/range_entropy.py +7 -7
  115. junifer/markers/complexity/range_entropy_auc.py +7 -7
  116. junifer/markers/complexity/sample_entropy.py +7 -7
  117. junifer/markers/complexity/tests/test_complexity_base.py +1 -1
  118. junifer/markers/complexity/tests/test_hurst_exponent.py +5 -5
  119. junifer/markers/complexity/tests/test_multiscale_entropy_auc.py +5 -5
  120. junifer/markers/complexity/tests/test_perm_entropy.py +5 -5
  121. junifer/markers/complexity/tests/test_range_entropy.py +5 -5
  122. junifer/markers/complexity/tests/test_range_entropy_auc.py +5 -5
  123. junifer/markers/complexity/tests/test_sample_entropy.py +5 -5
  124. junifer/markers/complexity/tests/test_weighted_perm_entropy.py +5 -5
  125. junifer/markers/complexity/weighted_perm_entropy.py +7 -7
  126. junifer/markers/ets_rss.py +12 -11
  127. junifer/markers/falff/__init__.py +2 -3
  128. junifer/markers/falff/__init__.pyi +4 -0
  129. junifer/markers/falff/_afni_falff.py +38 -45
  130. junifer/markers/falff/_junifer_falff.py +16 -19
  131. junifer/markers/falff/falff_base.py +7 -11
  132. junifer/markers/falff/falff_parcels.py +9 -9
  133. junifer/markers/falff/falff_spheres.py +8 -8
  134. junifer/markers/falff/py.typed +0 -0
  135. junifer/markers/falff/tests/test_falff_spheres.py +3 -1
  136. junifer/markers/functional_connectivity/__init__.py +2 -12
  137. junifer/markers/functional_connectivity/__init__.pyi +13 -0
  138. junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +9 -8
  139. junifer/markers/functional_connectivity/edge_functional_connectivity_parcels.py +8 -8
  140. junifer/markers/functional_connectivity/edge_functional_connectivity_spheres.py +7 -7
  141. junifer/markers/functional_connectivity/functional_connectivity_base.py +13 -12
  142. junifer/markers/functional_connectivity/functional_connectivity_parcels.py +8 -8
  143. junifer/markers/functional_connectivity/functional_connectivity_spheres.py +7 -7
  144. junifer/markers/functional_connectivity/py.typed +0 -0
  145. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_parcels.py +1 -2
  146. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_spheres.py +1 -2
  147. junifer/markers/functional_connectivity/tests/test_functional_connectivity_parcels.py +6 -6
  148. junifer/markers/functional_connectivity/tests/test_functional_connectivity_spheres.py +5 -5
  149. junifer/markers/parcel_aggregation.py +22 -17
  150. junifer/markers/py.typed +0 -0
  151. junifer/markers/reho/__init__.py +2 -3
  152. junifer/markers/reho/__init__.pyi +4 -0
  153. junifer/markers/reho/_afni_reho.py +29 -35
  154. junifer/markers/reho/_junifer_reho.py +13 -14
  155. junifer/markers/reho/py.typed +0 -0
  156. junifer/markers/reho/reho_base.py +7 -11
  157. junifer/markers/reho/reho_parcels.py +10 -10
  158. junifer/markers/reho/reho_spheres.py +9 -9
  159. junifer/markers/sphere_aggregation.py +22 -17
  160. junifer/markers/temporal_snr/__init__.py +2 -3
  161. junifer/markers/temporal_snr/__init__.pyi +4 -0
  162. junifer/markers/temporal_snr/py.typed +0 -0
  163. junifer/markers/temporal_snr/temporal_snr_base.py +11 -10
  164. junifer/markers/temporal_snr/temporal_snr_parcels.py +8 -8
  165. junifer/markers/temporal_snr/temporal_snr_spheres.py +7 -7
  166. junifer/markers/tests/test_ets_rss.py +3 -3
  167. junifer/markers/tests/test_parcel_aggregation.py +24 -24
  168. junifer/markers/tests/test_sphere_aggregation.py +6 -6
  169. junifer/markers/utils.py +3 -3
  170. junifer/onthefly/__init__.py +2 -1
  171. junifer/onthefly/_brainprint.py +138 -0
  172. junifer/onthefly/read_transform.py +5 -8
  173. junifer/pipeline/__init__.py +2 -10
  174. junifer/pipeline/__init__.pyi +13 -0
  175. junifer/{markers/collection.py → pipeline/marker_collection.py} +8 -14
  176. junifer/pipeline/pipeline_component_registry.py +294 -0
  177. junifer/pipeline/pipeline_step_mixin.py +15 -11
  178. junifer/pipeline/py.typed +0 -0
  179. junifer/{markers/tests/test_collection.py → pipeline/tests/test_marker_collection.py} +2 -3
  180. junifer/pipeline/tests/test_pipeline_component_registry.py +200 -0
  181. junifer/pipeline/tests/test_pipeline_step_mixin.py +36 -37
  182. junifer/pipeline/tests/test_update_meta_mixin.py +4 -4
  183. junifer/pipeline/tests/test_workdir_manager.py +43 -0
  184. junifer/pipeline/update_meta_mixin.py +21 -17
  185. junifer/pipeline/utils.py +6 -6
  186. junifer/pipeline/workdir_manager.py +19 -5
  187. junifer/preprocess/__init__.py +2 -10
  188. junifer/preprocess/__init__.pyi +11 -0
  189. junifer/preprocess/base.py +10 -10
  190. junifer/preprocess/confounds/__init__.py +2 -2
  191. junifer/preprocess/confounds/__init__.pyi +3 -0
  192. junifer/preprocess/confounds/fmriprep_confound_remover.py +243 -64
  193. junifer/preprocess/confounds/py.typed +0 -0
  194. junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py +121 -14
  195. junifer/preprocess/py.typed +0 -0
  196. junifer/preprocess/smoothing/__init__.py +2 -2
  197. junifer/preprocess/smoothing/__init__.pyi +3 -0
  198. junifer/preprocess/smoothing/_afni_smoothing.py +40 -40
  199. junifer/preprocess/smoothing/_fsl_smoothing.py +22 -32
  200. junifer/preprocess/smoothing/_nilearn_smoothing.py +35 -14
  201. junifer/preprocess/smoothing/py.typed +0 -0
  202. junifer/preprocess/smoothing/smoothing.py +11 -13
  203. junifer/preprocess/warping/__init__.py +2 -2
  204. junifer/preprocess/warping/__init__.pyi +3 -0
  205. junifer/preprocess/warping/_ants_warper.py +136 -32
  206. junifer/preprocess/warping/_fsl_warper.py +73 -22
  207. junifer/preprocess/warping/py.typed +0 -0
  208. junifer/preprocess/warping/space_warper.py +39 -11
  209. junifer/preprocess/warping/tests/test_space_warper.py +5 -9
  210. junifer/py.typed +0 -0
  211. junifer/stats.py +5 -5
  212. junifer/storage/__init__.py +2 -10
  213. junifer/storage/__init__.pyi +11 -0
  214. junifer/storage/base.py +47 -13
  215. junifer/storage/hdf5.py +95 -33
  216. junifer/storage/pandas_base.py +12 -11
  217. junifer/storage/py.typed +0 -0
  218. junifer/storage/sqlite.py +11 -11
  219. junifer/storage/tests/test_hdf5.py +86 -4
  220. junifer/storage/tests/test_sqlite.py +2 -2
  221. junifer/storage/tests/test_storage_base.py +5 -2
  222. junifer/storage/tests/test_utils.py +33 -7
  223. junifer/storage/utils.py +95 -9
  224. junifer/testing/__init__.py +2 -3
  225. junifer/testing/__init__.pyi +4 -0
  226. junifer/testing/datagrabbers.py +10 -11
  227. junifer/testing/py.typed +0 -0
  228. junifer/testing/registry.py +4 -7
  229. junifer/testing/tests/test_testing_registry.py +9 -17
  230. junifer/tests/test_stats.py +2 -2
  231. junifer/typing/__init__.py +9 -0
  232. junifer/typing/__init__.pyi +31 -0
  233. junifer/typing/_typing.py +68 -0
  234. junifer/utils/__init__.py +2 -12
  235. junifer/utils/__init__.pyi +18 -0
  236. junifer/utils/_config.py +110 -0
  237. junifer/utils/_yaml.py +16 -0
  238. junifer/utils/helpers.py +6 -6
  239. junifer/utils/logging.py +117 -8
  240. junifer/utils/py.typed +0 -0
  241. junifer/{pipeline → utils}/singleton.py +19 -14
  242. junifer/utils/tests/test_config.py +59 -0
  243. {junifer-0.0.5.dev240.dist-info → junifer-0.0.6.dist-info}/METADATA +43 -38
  244. junifer-0.0.6.dist-info/RECORD +350 -0
  245. {junifer-0.0.5.dev240.dist-info → junifer-0.0.6.dist-info}/WHEEL +1 -1
  246. junifer-0.0.6.dist-info/entry_points.txt +2 -0
  247. junifer/api/parser.py +0 -118
  248. junifer/data/coordinates.py +0 -408
  249. junifer/data/masks.py +0 -670
  250. junifer/data/parcellations.py +0 -1828
  251. junifer/pipeline/registry.py +0 -177
  252. junifer/pipeline/tests/test_registry.py +0 -150
  253. junifer-0.0.5.dev240.dist-info/RECORD +0 -275
  254. junifer-0.0.5.dev240.dist-info/entry_points.txt +0 -2
  255. /junifer/{api → cli}/tests/data/gmd_mean.yaml +0 -0
  256. /junifer/{api → cli}/tests/data/gmd_mean_htcondor.yaml +0 -0
  257. /junifer/{api → cli}/tests/data/partly_cloudy_agg_mean_tian.yml +0 -0
  258. /junifer/data/{VOIs → coordinates/VOIs}/meta/AutobiographicalMemory_VOIs.txt +0 -0
  259. /junifer/data/{VOIs → coordinates/VOIs}/meta/CogAC_VOIs.txt +0 -0
  260. /junifer/data/{VOIs → coordinates/VOIs}/meta/CogAR_VOIs.txt +0 -0
  261. /junifer/data/{VOIs → coordinates/VOIs}/meta/DMNBuckner_VOIs.txt +0 -0
  262. /junifer/data/{VOIs → coordinates/VOIs}/meta/Dosenbach2010_MNI_VOIs.txt +0 -0
  263. /junifer/data/{VOIs → coordinates/VOIs}/meta/Empathy_VOIs.txt +0 -0
  264. /junifer/data/{VOIs → coordinates/VOIs}/meta/Motor_VOIs.txt +0 -0
  265. /junifer/data/{VOIs → coordinates/VOIs}/meta/MultiTask_VOIs.txt +0 -0
  266. /junifer/data/{VOIs → coordinates/VOIs}/meta/PhysioStress_VOIs.txt +0 -0
  267. /junifer/data/{VOIs → coordinates/VOIs}/meta/Power2011_MNI_VOIs.txt +0 -0
  268. /junifer/data/{VOIs → coordinates/VOIs}/meta/Power2013_MNI_VOIs.tsv +0 -0
  269. /junifer/data/{VOIs → coordinates/VOIs}/meta/Rew_VOIs.txt +0 -0
  270. /junifer/data/{VOIs → coordinates/VOIs}/meta/Somatosensory_VOIs.txt +0 -0
  271. /junifer/data/{VOIs → coordinates/VOIs}/meta/ToM_VOIs.txt +0 -0
  272. /junifer/data/{VOIs → coordinates/VOIs}/meta/VigAtt_VOIs.txt +0 -0
  273. /junifer/data/{VOIs → coordinates/VOIs}/meta/WM_VOIs.txt +0 -0
  274. /junifer/data/{VOIs → coordinates/VOIs}/meta/eMDN_VOIs.txt +0 -0
  275. /junifer/data/{VOIs → coordinates/VOIs}/meta/eSAD_VOIs.txt +0 -0
  276. /junifer/data/{VOIs → coordinates/VOIs}/meta/extDMN_VOIs.txt +0 -0
  277. {junifer-0.0.5.dev240.dist-info → junifer-0.0.6.dist-info/licenses}/AUTHORS.rst +0 -0
  278. {junifer-0.0.5.dev240.dist-info → junifer-0.0.6.dist-info/licenses}/LICENSE.md +0 -0
  279. {junifer-0.0.5.dev240.dist-info → junifer-0.0.6.dist-info}/top_level.txt +0 -0
@@ -8,11 +8,12 @@
8
8
  import re
9
9
  from copy import deepcopy
10
10
  from pathlib import Path
11
- from typing import Dict, List, Optional, Tuple, Union
11
+ from typing import Optional, Union
12
12
 
13
13
  import numpy as np
14
14
 
15
15
  from ..api.decorators import register_datagrabber
16
+ from ..typing import DataGrabberPatterns, Elements
16
17
  from ..utils import logger, raise_error
17
18
  from .base import BaseDataGrabber
18
19
  from .pattern_validation_mixin import PatternValidationMixin
@@ -89,7 +90,7 @@ class PatternDataGrabber(BaseDataGrabber, PatternValidationMixin):
89
90
  .. code-block:: none
90
91
 
91
92
  {
92
- "mandatory": ["pattern", "src", "dst"],
93
+ "mandatory": ["pattern", "src", "dst", "warper"],
93
94
  "optional": []
94
95
  }
95
96
 
@@ -127,11 +128,22 @@ class PatternDataGrabber(BaseDataGrabber, PatternValidationMixin):
127
128
  "pattern": "...",
128
129
  "space": "...",
129
130
  },
130
- "Warp": {
131
- "pattern": "...",
132
- "src": "...",
133
- "dst": "...",
134
- }
131
+ }
132
+
133
+ except ``Warp``, which needs to be a list of dictionaries as there can
134
+ be multiple spaces to warp (for example, with fMRIPrep):
135
+
136
+ .. code-block:: none
137
+
138
+ {
139
+ "Warp": [
140
+ {
141
+ "pattern": "...",
142
+ "src": "...",
143
+ "dst": "...",
144
+ "warper": "...",
145
+ },
146
+ ],
135
147
  }
136
148
 
137
149
  taken from :class:`.HCP1200`.
@@ -159,9 +171,9 @@ class PatternDataGrabber(BaseDataGrabber, PatternValidationMixin):
159
171
 
160
172
  def __init__(
161
173
  self,
162
- types: List[str],
163
- patterns: Dict[str, Dict[str, str]],
164
- replacements: Union[List[str], str],
174
+ types: list[str],
175
+ patterns: DataGrabberPatterns,
176
+ replacements: Union[list[str], str],
165
177
  datadir: Union[str, Path],
166
178
  confounds_format: Optional[str] = None,
167
179
  partial_pattern_ok: bool = False,
@@ -204,7 +216,7 @@ class PatternDataGrabber(BaseDataGrabber, PatternValidationMixin):
204
216
 
205
217
  def _replace_patterns_regex(
206
218
  self, pattern: str
207
- ) -> Tuple[str, str, List[str]]:
219
+ ) -> tuple[str, str, list[str]]:
208
220
  """Replace the patterns in ``pattern`` with the named groups.
209
221
 
210
222
  It allows elements to be obtained from the filesystem.
@@ -250,7 +262,7 @@ class PatternDataGrabber(BaseDataGrabber, PatternValidationMixin):
250
262
 
251
263
  return re_pattern, glob_pattern, t_replacements
252
264
 
253
- def _replace_patterns_glob(self, element: Dict, pattern: str) -> str:
265
+ def _replace_patterns_glob(self, element: dict, pattern: str) -> str:
254
266
  """Replace ``pattern`` with the ``element`` so it can be globbed.
255
267
 
256
268
  Parameters
@@ -283,7 +295,7 @@ class PatternDataGrabber(BaseDataGrabber, PatternValidationMixin):
283
295
  return pattern.format(**element)
284
296
 
285
297
  def _get_path_from_patterns(
286
- self, element: Dict, pattern: str, data_type: str
298
+ self, element: dict, pattern: str, data_type: str
287
299
  ) -> Path:
288
300
  """Get path from resolved patterns.
289
301
 
@@ -340,7 +352,7 @@ class PatternDataGrabber(BaseDataGrabber, PatternValidationMixin):
340
352
 
341
353
  return path
342
354
 
343
- def get_element_keys(self) -> List[str]:
355
+ def get_element_keys(self) -> list[str]:
344
356
  """Get element keys.
345
357
 
346
358
  For each item in the "element" tuple, this functions returns the
@@ -355,7 +367,7 @@ class PatternDataGrabber(BaseDataGrabber, PatternValidationMixin):
355
367
  """
356
368
  return self.replacements
357
369
 
358
- def get_item(self, **element: str) -> Dict[str, Dict]:
370
+ def get_item(self, **element: dict) -> dict[str, dict]:
359
371
  """Implement single element indexing for the datagrabber.
360
372
 
361
373
  This method constructs a real path to the requested item's data, by
@@ -380,46 +392,65 @@ class PatternDataGrabber(BaseDataGrabber, PatternValidationMixin):
380
392
  t_pattern = self.patterns[t_type]
381
393
  # Copy data type dictionary in output
382
394
  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}")
395
+ # Conditional for list dtype vals like Warp
396
+ if isinstance(t_pattern, list):
397
+ for idx, entry in enumerate(t_pattern):
398
+ logger.info(
399
+ f"Resolving path from pattern for {t_type}.{idx}"
400
+ )
388
401
  # Resolve pattern
389
- base_data_type_pattern_path = self._get_path_from_patterns(
402
+ dtype_pattern_path = self._get_path_from_patterns(
390
403
  element=element,
391
- pattern=v,
392
- data_type=t_type,
404
+ pattern=entry["pattern"],
405
+ data_type=f"{t_type}.{idx}",
393
406
  )
394
407
  # Remove pattern key
395
- out[t_type].pop("pattern")
408
+ out[t_type][idx].pop("pattern")
396
409
  # 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}"
404
- )
405
- # Resolve pattern
406
- nested_data_type_pattern_path = (
407
- self._get_path_from_patterns(
410
+ out[t_type][idx].update({"path": dtype_pattern_path})
411
+ else:
412
+ # Iterate to check for nested "types" like mask
413
+ for k, v in t_pattern.items():
414
+ # Resolve pattern for base data type
415
+ if k == "pattern":
416
+ logger.info(
417
+ f"Resolving path from pattern for {t_type}"
418
+ )
419
+ # Resolve pattern
420
+ base_dtype_pattern_path = self._get_path_from_patterns(
408
421
  element=element,
409
- pattern=v["pattern"],
410
- data_type=t_nested_type,
422
+ pattern=v,
423
+ data_type=t_type,
424
+ )
425
+ # Remove pattern key
426
+ out[t_type].pop("pattern")
427
+ # Add path key
428
+ out[t_type].update({"path": base_dtype_pattern_path})
429
+ # Resolve pattern for nested data type
430
+ if isinstance(v, dict) and "pattern" in v:
431
+ # Set nested type key for easier access
432
+ t_nested_type = f"{t_type}.{k}"
433
+ logger.info(
434
+ f"Resolving path from pattern for {t_nested_type}"
435
+ )
436
+ # Resolve pattern
437
+ nested_dtype_pattern_path = (
438
+ self._get_path_from_patterns(
439
+ element=element,
440
+ pattern=v["pattern"],
441
+ data_type=t_nested_type,
442
+ )
443
+ )
444
+ # Remove pattern key
445
+ out[t_type][k].pop("pattern")
446
+ # Add path key
447
+ out[t_type][k].update(
448
+ {"path": nested_dtype_pattern_path}
411
449
  )
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
- )
419
450
 
420
451
  return out
421
452
 
422
- def get_elements(self) -> List:
453
+ def get_elements(self) -> Elements:
423
454
  """Implement fetching list of elements in the dataset.
424
455
 
425
456
  It will use regex to search for "replacements" in the "patterns" and
@@ -448,58 +479,63 @@ class PatternDataGrabber(BaseDataGrabber, PatternValidationMixin):
448
479
  t_type = self.types[t_idx]
449
480
  types_element = set()
450
481
 
451
- # Get the pattern dict
452
- 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
- # Replace the pattern
465
- (
466
- re_pattern,
467
- glob_pattern,
468
- t_replacements,
469
- ) = self._replace_patterns_regex(pattern)
470
- for fname in self.datadir.glob(glob_pattern):
471
- suffix = fname.relative_to(self.datadir).as_posix()
472
- m = re.match(re_pattern, suffix)
473
- if m is not None:
474
- # Find the groups of replacements present in the pattern
475
- # If one replacement is not present, set it to None.
476
- # We will take care of this in the intersection
477
- t_element = tuple([m.group(k) for k in t_replacements])
478
- if len(self.replacements) == 1:
479
- t_element = t_element[0]
480
- types_element.add(t_element)
481
- # TODO: does this make sense as elements is always None
482
- if elements is None:
483
- elements = types_element
484
- else:
485
- # Do the intersection by filtering out elements in which
486
- # the replacements are not None
487
- if t_replacements == self.replacements:
488
- elements.intersection(types_element)
482
+ # Data type dictionary
483
+ patterns = self.patterns[t_type]
484
+ # Conditional for list dtype vals like Warp
485
+ if not isinstance(patterns, list):
486
+ patterns = [patterns]
487
+ for t_pattern in patterns:
488
+ # Conditional fetch of base pattern for getting elements
489
+ pattern = None
490
+ # Try for data type pattern
491
+ pattern = t_pattern.get("pattern")
492
+ # Try for nested data type pattern
493
+ if pattern is None and self.partial_pattern_ok:
494
+ for v in t_pattern.values():
495
+ if isinstance(v, dict) and "pattern" in v:
496
+ pattern = v["pattern"]
497
+ break
498
+
499
+ # Replace the pattern
500
+ (
501
+ re_pattern,
502
+ glob_pattern,
503
+ t_replacements,
504
+ ) = self._replace_patterns_regex(pattern)
505
+ for fname in self.datadir.glob(glob_pattern):
506
+ suffix = fname.relative_to(self.datadir).as_posix()
507
+ m = re.match(re_pattern, suffix)
508
+ if m is not None:
509
+ # Find the groups of replacements present in the
510
+ # pattern. If one replacement is not present, set it
511
+ # to None. We will take care of this in the
512
+ # intersection.
513
+ t_element = tuple([m.group(k) for k in t_replacements])
514
+ if len(self.replacements) == 1:
515
+ t_element = t_element[0]
516
+ types_element.add(t_element)
517
+ # TODO: does this make sense as elements is always None
518
+ if elements is None:
519
+ elements = types_element
489
520
  else:
490
- t_repl_idx = [
491
- i
492
- for i, v in enumerate(self.replacements)
493
- if v in t_replacements
494
- ]
495
- new_elements = set()
496
- for t_element in elements:
497
- if (
498
- tuple(np.array(t_element)[t_repl_idx])
499
- in types_element
500
- ):
501
- new_elements.add(t_element)
502
- elements = new_elements
521
+ # Do the intersection by filtering out elements in which
522
+ # the replacements are not None
523
+ if t_replacements == self.replacements:
524
+ elements.intersection(types_element)
525
+ else:
526
+ t_repl_idx = [
527
+ i
528
+ for i, v in enumerate(self.replacements)
529
+ if v in t_replacements
530
+ ]
531
+ new_elements = set()
532
+ for t_element in elements:
533
+ if (
534
+ tuple(np.array(t_element)[t_repl_idx])
535
+ in types_element
536
+ ):
537
+ new_elements.add(t_element)
538
+ elements = new_elements
503
539
  if elements is None:
504
540
  elements = set()
505
541
  return list(elements)