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.
- junifer/__init__.py +0 -17
- junifer/_version.py +2 -2
- junifer/api/__init__.py +1 -4
- junifer/api/cli.py +1 -91
- junifer/api/decorators.py +0 -9
- junifer/api/functions.py +10 -56
- junifer/api/parser.py +0 -3
- junifer/api/queue_context/__init__.py +1 -4
- junifer/api/res/afni/run_afni_docker.sh +1 -1
- junifer/api/res/ants/run_ants_docker.sh +1 -1
- junifer/api/res/fsl/run_fsl_docker.sh +1 -1
- junifer/api/tests/test_api_utils.py +2 -4
- junifer/api/tests/test_cli.py +0 -83
- junifer/api/tests/test_functions.py +2 -27
- junifer/configs/__init__.py +1 -1
- junifer/configs/juseless/__init__.py +1 -4
- junifer/configs/juseless/datagrabbers/__init__.py +1 -10
- junifer/configs/juseless/datagrabbers/aomic_id1000_vbm.py +0 -3
- junifer/configs/juseless/datagrabbers/camcan_vbm.py +0 -3
- junifer/configs/juseless/datagrabbers/ixi_vbm.py +0 -3
- junifer/configs/juseless/datagrabbers/tests/test_ucla.py +3 -1
- junifer/configs/juseless/datagrabbers/ucla.py +9 -12
- junifer/configs/juseless/datagrabbers/ukb_vbm.py +0 -3
- junifer/data/__init__.py +1 -21
- junifer/data/coordinates.py +19 -10
- junifer/data/masks.py +87 -58
- junifer/data/parcellations.py +3 -14
- junifer/data/template_spaces.py +1 -4
- junifer/data/tests/test_masks.py +37 -26
- junifer/data/utils.py +0 -3
- junifer/datagrabber/__init__.py +1 -18
- junifer/datagrabber/aomic/__init__.py +0 -3
- junifer/datagrabber/aomic/id1000.py +37 -70
- junifer/datagrabber/aomic/piop1.py +36 -69
- junifer/datagrabber/aomic/piop2.py +38 -71
- junifer/datagrabber/aomic/tests/test_id1000.py +99 -44
- junifer/datagrabber/aomic/tests/test_piop1.py +108 -65
- junifer/datagrabber/aomic/tests/test_piop2.py +102 -45
- junifer/datagrabber/base.py +6 -13
- junifer/datagrabber/datalad_base.py +1 -13
- junifer/datagrabber/dmcc13_benchmark.py +53 -36
- junifer/datagrabber/hcp1200/__init__.py +0 -3
- junifer/datagrabber/hcp1200/datalad_hcp1200.py +0 -3
- junifer/datagrabber/hcp1200/hcp1200.py +1 -4
- junifer/datagrabber/multiple.py +6 -45
- junifer/datagrabber/pattern.py +62 -170
- junifer/datagrabber/pattern_datalad.py +12 -25
- junifer/datagrabber/tests/test_datagrabber_utils.py +218 -0
- junifer/datagrabber/tests/test_datalad_base.py +4 -4
- junifer/datagrabber/tests/test_dmcc13_benchmark.py +19 -46
- junifer/datagrabber/tests/test_multiple.py +84 -161
- junifer/datagrabber/tests/test_pattern.py +0 -45
- junifer/datagrabber/tests/test_pattern_datalad.py +4 -4
- junifer/datagrabber/utils.py +230 -0
- junifer/datareader/__init__.py +1 -4
- junifer/datareader/default.py +43 -95
- junifer/external/__init__.py +1 -1
- junifer/external/nilearn/__init__.py +1 -5
- junifer/external/nilearn/junifer_nifti_spheres_masker.py +9 -23
- junifer/external/nilearn/tests/test_junifer_nifti_spheres_masker.py +1 -76
- junifer/markers/__init__.py +1 -23
- junifer/markers/base.py +28 -68
- junifer/markers/collection.py +2 -10
- junifer/markers/complexity/__init__.py +0 -10
- junifer/markers/complexity/complexity_base.py +43 -26
- junifer/markers/complexity/hurst_exponent.py +0 -3
- junifer/markers/complexity/multiscale_entropy_auc.py +0 -3
- junifer/markers/complexity/perm_entropy.py +0 -3
- junifer/markers/complexity/range_entropy.py +0 -3
- junifer/markers/complexity/range_entropy_auc.py +0 -3
- junifer/markers/complexity/sample_entropy.py +0 -3
- junifer/markers/complexity/tests/test_hurst_exponent.py +3 -11
- junifer/markers/complexity/tests/test_multiscale_entropy_auc.py +3 -11
- junifer/markers/complexity/tests/test_perm_entropy.py +3 -11
- junifer/markers/complexity/tests/test_range_entropy.py +3 -11
- junifer/markers/complexity/tests/test_range_entropy_auc.py +3 -11
- junifer/markers/complexity/tests/test_sample_entropy.py +3 -11
- junifer/markers/complexity/tests/test_weighted_perm_entropy.py +3 -11
- junifer/markers/complexity/weighted_perm_entropy.py +0 -3
- junifer/markers/ets_rss.py +42 -27
- junifer/markers/falff/__init__.py +0 -3
- junifer/markers/falff/_afni_falff.py +2 -5
- junifer/markers/falff/_junifer_falff.py +0 -3
- junifer/markers/falff/falff_base.py +46 -20
- junifer/markers/falff/falff_parcels.py +27 -56
- junifer/markers/falff/falff_spheres.py +29 -60
- junifer/markers/falff/tests/test_falff_parcels.py +23 -39
- junifer/markers/falff/tests/test_falff_spheres.py +23 -39
- junifer/markers/functional_connectivity/__init__.py +0 -9
- junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +60 -63
- junifer/markers/functional_connectivity/edge_functional_connectivity_parcels.py +32 -45
- junifer/markers/functional_connectivity/edge_functional_connectivity_spheres.py +36 -49
- junifer/markers/functional_connectivity/functional_connectivity_base.py +70 -71
- junifer/markers/functional_connectivity/functional_connectivity_parcels.py +25 -34
- junifer/markers/functional_connectivity/functional_connectivity_spheres.py +30 -40
- junifer/markers/functional_connectivity/tests/test_crossparcellation_functional_connectivity.py +7 -11
- junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_parcels.py +7 -27
- junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_spheres.py +12 -28
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_parcels.py +11 -35
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_spheres.py +62 -36
- junifer/markers/parcel_aggregation.py +61 -47
- junifer/markers/reho/__init__.py +0 -3
- junifer/markers/reho/_afni_reho.py +2 -5
- junifer/markers/reho/_junifer_reho.py +1 -4
- junifer/markers/reho/reho_base.py +27 -8
- junifer/markers/reho/reho_parcels.py +17 -28
- junifer/markers/reho/reho_spheres.py +18 -27
- junifer/markers/reho/tests/test_reho_parcels.py +3 -8
- junifer/markers/reho/tests/test_reho_spheres.py +3 -8
- junifer/markers/sphere_aggregation.py +59 -43
- junifer/markers/temporal_snr/__init__.py +0 -3
- junifer/markers/temporal_snr/temporal_snr_base.py +32 -23
- junifer/markers/temporal_snr/temporal_snr_parcels.py +6 -9
- junifer/markers/temporal_snr/temporal_snr_spheres.py +6 -9
- junifer/markers/temporal_snr/tests/test_temporal_snr_parcels.py +3 -6
- junifer/markers/temporal_snr/tests/test_temporal_snr_spheres.py +3 -6
- junifer/markers/tests/test_collection.py +8 -9
- junifer/markers/tests/test_ets_rss.py +9 -15
- junifer/markers/tests/test_markers_base.py +18 -17
- junifer/markers/tests/test_parcel_aggregation.py +32 -93
- junifer/markers/tests/test_sphere_aggregation.py +19 -72
- junifer/onthefly/__init__.py +1 -4
- junifer/onthefly/read_transform.py +0 -3
- junifer/pipeline/__init__.py +1 -9
- junifer/pipeline/pipeline_step_mixin.py +4 -21
- junifer/pipeline/registry.py +0 -3
- junifer/pipeline/singleton.py +0 -3
- junifer/pipeline/tests/test_registry.py +1 -1
- junifer/pipeline/update_meta_mixin.py +0 -3
- junifer/pipeline/utils.py +1 -67
- junifer/pipeline/workdir_manager.py +0 -3
- junifer/preprocess/__init__.py +2 -9
- junifer/preprocess/ants/__init__.py +4 -0
- junifer/preprocess/ants/ants_apply_transforms_warper.py +185 -0
- junifer/preprocess/ants/tests/test_ants_apply_transforms_warper.py +56 -0
- junifer/preprocess/base.py +3 -6
- junifer/preprocess/bold_warper.py +265 -0
- junifer/preprocess/confounds/__init__.py +0 -3
- junifer/preprocess/confounds/fmriprep_confound_remover.py +60 -47
- junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py +113 -72
- junifer/preprocess/fsl/__init__.py +4 -0
- junifer/preprocess/fsl/apply_warper.py +179 -0
- junifer/preprocess/fsl/tests/test_apply_warper.py +45 -0
- junifer/preprocess/smoothing/__init__.py +0 -3
- junifer/preprocess/smoothing/_afni_smoothing.py +1 -1
- junifer/preprocess/tests/test_bold_warper.py +159 -0
- junifer/preprocess/warping/__init__.py +0 -3
- junifer/preprocess/warping/_ants_warper.py +0 -3
- junifer/preprocess/warping/_fsl_warper.py +0 -3
- junifer/stats.py +1 -4
- junifer/storage/__init__.py +1 -9
- junifer/storage/base.py +1 -40
- junifer/storage/hdf5.py +9 -71
- junifer/storage/pandas_base.py +0 -3
- junifer/storage/sqlite.py +0 -3
- junifer/storage/tests/test_hdf5.py +10 -82
- junifer/storage/utils.py +0 -9
- junifer/testing/__init__.py +1 -4
- junifer/testing/datagrabbers.py +6 -13
- junifer/testing/tests/test_partlycloudytesting_datagrabber.py +7 -7
- junifer/testing/utils.py +0 -3
- junifer/utils/__init__.py +2 -13
- junifer/utils/fs.py +0 -3
- junifer/utils/helpers.py +1 -32
- junifer/utils/logging.py +4 -33
- junifer/utils/tests/test_logging.py +0 -8
- {junifer-0.0.5.dist-info → junifer-0.0.5.dev24.dist-info}/METADATA +16 -17
- junifer-0.0.5.dev24.dist-info/RECORD +265 -0
- {junifer-0.0.5.dist-info → junifer-0.0.5.dev24.dist-info}/WHEEL +1 -1
- junifer/api/res/freesurfer/mri_binarize +0 -3
- junifer/api/res/freesurfer/mri_mc +0 -3
- junifer/api/res/freesurfer/mri_pretess +0 -3
- junifer/api/res/freesurfer/mris_convert +0 -3
- junifer/api/res/freesurfer/run_freesurfer_docker.sh +0 -61
- junifer/data/masks/ukb/UKB_15K_GM_template.nii.gz +0 -0
- junifer/datagrabber/pattern_validation_mixin.py +0 -388
- junifer/datagrabber/tests/test_pattern_validation_mixin.py +0 -249
- junifer/external/BrainPrint/brainprint/__init__.py +0 -4
- junifer/external/BrainPrint/brainprint/_version.py +0 -3
- junifer/external/BrainPrint/brainprint/asymmetry.py +0 -91
- junifer/external/BrainPrint/brainprint/brainprint.py +0 -441
- junifer/external/BrainPrint/brainprint/surfaces.py +0 -258
- junifer/external/BrainPrint/brainprint/utils/__init__.py +0 -1
- junifer/external/BrainPrint/brainprint/utils/_config.py +0 -112
- junifer/external/BrainPrint/brainprint/utils/utils.py +0 -188
- junifer/external/nilearn/junifer_connectivity_measure.py +0 -483
- junifer/external/nilearn/tests/test_junifer_connectivity_measure.py +0 -1089
- junifer/markers/brainprint.py +0 -459
- junifer/markers/tests/test_brainprint.py +0 -58
- junifer-0.0.5.dist-info/RECORD +0 -275
- {junifer-0.0.5.dist-info → junifer-0.0.5.dev24.dist-info}/AUTHORS.rst +0 -0
- {junifer-0.0.5.dist-info → junifer-0.0.5.dev24.dist-info}/LICENSE.md +0 -0
- {junifer-0.0.5.dist-info → junifer-0.0.5.dev24.dist-info}/entry_points.txt +0 -0
- {junifer-0.0.5.dist-info → junifer-0.0.5.dev24.dist-info}/top_level.txt +0 -0
junifer/datagrabber/multiple.py
CHANGED
@@ -7,15 +7,10 @@
|
|
7
7
|
|
8
8
|
from typing import Dict, List, Tuple, Union
|
9
9
|
|
10
|
-
from ..
|
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
|
-
#
|
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
|
-
|
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
|
-
|
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
|
-
|
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")
|
junifer/datagrabber/pattern.py
CHANGED
@@ -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 .
|
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
|
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
|
173
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
if
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
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
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
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
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
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
|
-
|
414
|
-
|
415
|
-
|
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
|