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.
- junifer/__init__.py +2 -31
- junifer/__init__.pyi +37 -0
- junifer/_version.py +9 -4
- junifer/api/__init__.py +3 -5
- junifer/api/__init__.pyi +4 -0
- junifer/api/decorators.py +14 -19
- junifer/api/functions.py +165 -109
- junifer/api/py.typed +0 -0
- junifer/api/queue_context/__init__.py +2 -4
- junifer/api/queue_context/__init__.pyi +5 -0
- junifer/api/queue_context/gnu_parallel_local_adapter.py +22 -6
- junifer/api/queue_context/htcondor_adapter.py +23 -6
- junifer/api/queue_context/py.typed +0 -0
- junifer/api/queue_context/tests/test_gnu_parallel_local_adapter.py +3 -3
- junifer/api/queue_context/tests/test_htcondor_adapter.py +3 -3
- junifer/api/tests/test_functions.py +168 -74
- junifer/cli/__init__.py +24 -0
- junifer/cli/__init__.pyi +3 -0
- junifer/{api → cli}/cli.py +141 -125
- junifer/cli/parser.py +235 -0
- junifer/cli/py.typed +0 -0
- junifer/{api → cli}/tests/test_cli.py +8 -8
- junifer/{api/tests/test_api_utils.py → cli/tests/test_cli_utils.py} +5 -4
- junifer/{api → cli}/tests/test_parser.py +2 -2
- junifer/{api → cli}/utils.py +6 -16
- junifer/configs/juseless/__init__.py +2 -2
- junifer/configs/juseless/__init__.pyi +3 -0
- junifer/configs/juseless/datagrabbers/__init__.py +2 -12
- junifer/configs/juseless/datagrabbers/__init__.pyi +13 -0
- junifer/configs/juseless/datagrabbers/ixi_vbm.py +2 -2
- junifer/configs/juseless/datagrabbers/py.typed +0 -0
- junifer/configs/juseless/datagrabbers/tests/test_ucla.py +2 -2
- junifer/configs/juseless/datagrabbers/ucla.py +4 -4
- junifer/configs/juseless/py.typed +0 -0
- junifer/conftest.py +25 -0
- junifer/data/__init__.py +2 -42
- junifer/data/__init__.pyi +29 -0
- junifer/data/_dispatch.py +248 -0
- junifer/data/coordinates/__init__.py +9 -0
- junifer/data/coordinates/__init__.pyi +5 -0
- junifer/data/coordinates/_ants_coordinates_warper.py +104 -0
- junifer/data/coordinates/_coordinates.py +385 -0
- junifer/data/coordinates/_fsl_coordinates_warper.py +81 -0
- junifer/data/{tests → coordinates/tests}/test_coordinates.py +26 -33
- junifer/data/masks/__init__.py +9 -0
- junifer/data/masks/__init__.pyi +6 -0
- junifer/data/masks/_ants_mask_warper.py +177 -0
- junifer/data/masks/_fsl_mask_warper.py +106 -0
- junifer/data/masks/_masks.py +802 -0
- junifer/data/{tests → masks/tests}/test_masks.py +67 -63
- junifer/data/parcellations/__init__.py +9 -0
- junifer/data/parcellations/__init__.pyi +6 -0
- junifer/data/parcellations/_ants_parcellation_warper.py +166 -0
- junifer/data/parcellations/_fsl_parcellation_warper.py +89 -0
- junifer/data/parcellations/_parcellations.py +1388 -0
- junifer/data/{tests → parcellations/tests}/test_parcellations.py +165 -295
- junifer/data/pipeline_data_registry_base.py +76 -0
- junifer/data/py.typed +0 -0
- junifer/data/template_spaces.py +44 -79
- junifer/data/tests/test_data_utils.py +1 -2
- junifer/data/tests/test_template_spaces.py +8 -4
- junifer/data/utils.py +109 -4
- junifer/datagrabber/__init__.py +2 -26
- junifer/datagrabber/__init__.pyi +27 -0
- junifer/datagrabber/aomic/__init__.py +2 -4
- junifer/datagrabber/aomic/__init__.pyi +5 -0
- junifer/datagrabber/aomic/id1000.py +81 -52
- junifer/datagrabber/aomic/piop1.py +83 -55
- junifer/datagrabber/aomic/piop2.py +85 -56
- junifer/datagrabber/aomic/py.typed +0 -0
- junifer/datagrabber/aomic/tests/test_id1000.py +19 -12
- junifer/datagrabber/aomic/tests/test_piop1.py +52 -18
- junifer/datagrabber/aomic/tests/test_piop2.py +50 -17
- junifer/datagrabber/base.py +22 -18
- junifer/datagrabber/datalad_base.py +71 -34
- junifer/datagrabber/dmcc13_benchmark.py +31 -18
- junifer/datagrabber/hcp1200/__init__.py +2 -3
- junifer/datagrabber/hcp1200/__init__.pyi +4 -0
- junifer/datagrabber/hcp1200/datalad_hcp1200.py +3 -3
- junifer/datagrabber/hcp1200/hcp1200.py +26 -15
- junifer/datagrabber/hcp1200/py.typed +0 -0
- junifer/datagrabber/hcp1200/tests/test_hcp1200.py +8 -2
- junifer/datagrabber/multiple.py +14 -9
- junifer/datagrabber/pattern.py +132 -96
- junifer/datagrabber/pattern_validation_mixin.py +206 -94
- junifer/datagrabber/py.typed +0 -0
- junifer/datagrabber/tests/test_datalad_base.py +27 -12
- junifer/datagrabber/tests/test_dmcc13_benchmark.py +28 -11
- junifer/datagrabber/tests/test_multiple.py +48 -2
- junifer/datagrabber/tests/test_pattern_datalad.py +1 -1
- junifer/datagrabber/tests/test_pattern_validation_mixin.py +6 -6
- junifer/datareader/__init__.py +2 -2
- junifer/datareader/__init__.pyi +3 -0
- junifer/datareader/default.py +6 -6
- junifer/datareader/py.typed +0 -0
- junifer/external/nilearn/__init__.py +2 -3
- junifer/external/nilearn/__init__.pyi +4 -0
- junifer/external/nilearn/junifer_connectivity_measure.py +25 -17
- junifer/external/nilearn/junifer_nifti_spheres_masker.py +4 -4
- junifer/external/nilearn/py.typed +0 -0
- junifer/external/nilearn/tests/test_junifer_connectivity_measure.py +17 -16
- junifer/external/nilearn/tests/test_junifer_nifti_spheres_masker.py +2 -3
- junifer/markers/__init__.py +2 -38
- junifer/markers/__init__.pyi +37 -0
- junifer/markers/base.py +11 -14
- junifer/markers/brainprint.py +12 -14
- junifer/markers/complexity/__init__.py +2 -18
- junifer/markers/complexity/__init__.pyi +17 -0
- junifer/markers/complexity/complexity_base.py +9 -11
- junifer/markers/complexity/hurst_exponent.py +7 -7
- junifer/markers/complexity/multiscale_entropy_auc.py +7 -7
- junifer/markers/complexity/perm_entropy.py +7 -7
- junifer/markers/complexity/py.typed +0 -0
- junifer/markers/complexity/range_entropy.py +7 -7
- junifer/markers/complexity/range_entropy_auc.py +7 -7
- junifer/markers/complexity/sample_entropy.py +7 -7
- junifer/markers/complexity/tests/test_complexity_base.py +1 -1
- junifer/markers/complexity/tests/test_hurst_exponent.py +5 -5
- junifer/markers/complexity/tests/test_multiscale_entropy_auc.py +5 -5
- junifer/markers/complexity/tests/test_perm_entropy.py +5 -5
- junifer/markers/complexity/tests/test_range_entropy.py +5 -5
- junifer/markers/complexity/tests/test_range_entropy_auc.py +5 -5
- junifer/markers/complexity/tests/test_sample_entropy.py +5 -5
- junifer/markers/complexity/tests/test_weighted_perm_entropy.py +5 -5
- junifer/markers/complexity/weighted_perm_entropy.py +7 -7
- junifer/markers/ets_rss.py +12 -11
- junifer/markers/falff/__init__.py +2 -3
- junifer/markers/falff/__init__.pyi +4 -0
- junifer/markers/falff/_afni_falff.py +38 -45
- junifer/markers/falff/_junifer_falff.py +16 -19
- junifer/markers/falff/falff_base.py +7 -11
- junifer/markers/falff/falff_parcels.py +9 -9
- junifer/markers/falff/falff_spheres.py +8 -8
- junifer/markers/falff/py.typed +0 -0
- junifer/markers/falff/tests/test_falff_spheres.py +3 -1
- junifer/markers/functional_connectivity/__init__.py +2 -12
- junifer/markers/functional_connectivity/__init__.pyi +13 -0
- junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +9 -8
- junifer/markers/functional_connectivity/edge_functional_connectivity_parcels.py +8 -8
- junifer/markers/functional_connectivity/edge_functional_connectivity_spheres.py +7 -7
- junifer/markers/functional_connectivity/functional_connectivity_base.py +13 -12
- junifer/markers/functional_connectivity/functional_connectivity_parcels.py +8 -8
- junifer/markers/functional_connectivity/functional_connectivity_spheres.py +7 -7
- junifer/markers/functional_connectivity/py.typed +0 -0
- junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_parcels.py +1 -2
- junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_spheres.py +1 -2
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_parcels.py +6 -6
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_spheres.py +5 -5
- junifer/markers/parcel_aggregation.py +22 -17
- junifer/markers/py.typed +0 -0
- junifer/markers/reho/__init__.py +2 -3
- junifer/markers/reho/__init__.pyi +4 -0
- junifer/markers/reho/_afni_reho.py +29 -35
- junifer/markers/reho/_junifer_reho.py +13 -14
- junifer/markers/reho/py.typed +0 -0
- junifer/markers/reho/reho_base.py +7 -11
- junifer/markers/reho/reho_parcels.py +10 -10
- junifer/markers/reho/reho_spheres.py +9 -9
- junifer/markers/sphere_aggregation.py +22 -17
- junifer/markers/temporal_snr/__init__.py +2 -3
- junifer/markers/temporal_snr/__init__.pyi +4 -0
- junifer/markers/temporal_snr/py.typed +0 -0
- junifer/markers/temporal_snr/temporal_snr_base.py +11 -10
- junifer/markers/temporal_snr/temporal_snr_parcels.py +8 -8
- junifer/markers/temporal_snr/temporal_snr_spheres.py +7 -7
- junifer/markers/tests/test_ets_rss.py +3 -3
- junifer/markers/tests/test_parcel_aggregation.py +24 -24
- junifer/markers/tests/test_sphere_aggregation.py +6 -6
- junifer/markers/utils.py +3 -3
- junifer/onthefly/__init__.py +2 -1
- junifer/onthefly/_brainprint.py +138 -0
- junifer/onthefly/read_transform.py +5 -8
- junifer/pipeline/__init__.py +2 -10
- junifer/pipeline/__init__.pyi +13 -0
- junifer/{markers/collection.py → pipeline/marker_collection.py} +8 -14
- junifer/pipeline/pipeline_component_registry.py +294 -0
- junifer/pipeline/pipeline_step_mixin.py +15 -11
- junifer/pipeline/py.typed +0 -0
- junifer/{markers/tests/test_collection.py → pipeline/tests/test_marker_collection.py} +2 -3
- junifer/pipeline/tests/test_pipeline_component_registry.py +200 -0
- junifer/pipeline/tests/test_pipeline_step_mixin.py +36 -37
- junifer/pipeline/tests/test_update_meta_mixin.py +4 -4
- junifer/pipeline/tests/test_workdir_manager.py +43 -0
- junifer/pipeline/update_meta_mixin.py +21 -17
- junifer/pipeline/utils.py +6 -6
- junifer/pipeline/workdir_manager.py +19 -5
- junifer/preprocess/__init__.py +2 -10
- junifer/preprocess/__init__.pyi +11 -0
- junifer/preprocess/base.py +10 -10
- junifer/preprocess/confounds/__init__.py +2 -2
- junifer/preprocess/confounds/__init__.pyi +3 -0
- junifer/preprocess/confounds/fmriprep_confound_remover.py +243 -64
- junifer/preprocess/confounds/py.typed +0 -0
- junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py +121 -14
- junifer/preprocess/py.typed +0 -0
- junifer/preprocess/smoothing/__init__.py +2 -2
- junifer/preprocess/smoothing/__init__.pyi +3 -0
- junifer/preprocess/smoothing/_afni_smoothing.py +40 -40
- junifer/preprocess/smoothing/_fsl_smoothing.py +22 -32
- junifer/preprocess/smoothing/_nilearn_smoothing.py +35 -14
- junifer/preprocess/smoothing/py.typed +0 -0
- junifer/preprocess/smoothing/smoothing.py +11 -13
- junifer/preprocess/warping/__init__.py +2 -2
- junifer/preprocess/warping/__init__.pyi +3 -0
- junifer/preprocess/warping/_ants_warper.py +136 -32
- junifer/preprocess/warping/_fsl_warper.py +73 -22
- junifer/preprocess/warping/py.typed +0 -0
- junifer/preprocess/warping/space_warper.py +39 -11
- junifer/preprocess/warping/tests/test_space_warper.py +5 -9
- junifer/py.typed +0 -0
- junifer/stats.py +5 -5
- junifer/storage/__init__.py +2 -10
- junifer/storage/__init__.pyi +11 -0
- junifer/storage/base.py +47 -13
- junifer/storage/hdf5.py +95 -33
- junifer/storage/pandas_base.py +12 -11
- junifer/storage/py.typed +0 -0
- junifer/storage/sqlite.py +11 -11
- junifer/storage/tests/test_hdf5.py +86 -4
- junifer/storage/tests/test_sqlite.py +2 -2
- junifer/storage/tests/test_storage_base.py +5 -2
- junifer/storage/tests/test_utils.py +33 -7
- junifer/storage/utils.py +95 -9
- junifer/testing/__init__.py +2 -3
- junifer/testing/__init__.pyi +4 -0
- junifer/testing/datagrabbers.py +10 -11
- junifer/testing/py.typed +0 -0
- junifer/testing/registry.py +4 -7
- junifer/testing/tests/test_testing_registry.py +9 -17
- junifer/tests/test_stats.py +2 -2
- junifer/typing/__init__.py +9 -0
- junifer/typing/__init__.pyi +31 -0
- junifer/typing/_typing.py +68 -0
- junifer/utils/__init__.py +2 -12
- junifer/utils/__init__.pyi +18 -0
- junifer/utils/_config.py +110 -0
- junifer/utils/_yaml.py +16 -0
- junifer/utils/helpers.py +6 -6
- junifer/utils/logging.py +117 -8
- junifer/utils/py.typed +0 -0
- junifer/{pipeline → utils}/singleton.py +19 -14
- junifer/utils/tests/test_config.py +59 -0
- {junifer-0.0.5.dev240.dist-info → junifer-0.0.6.dist-info}/METADATA +43 -38
- junifer-0.0.6.dist-info/RECORD +350 -0
- {junifer-0.0.5.dev240.dist-info → junifer-0.0.6.dist-info}/WHEEL +1 -1
- junifer-0.0.6.dist-info/entry_points.txt +2 -0
- junifer/api/parser.py +0 -118
- junifer/data/coordinates.py +0 -408
- junifer/data/masks.py +0 -670
- junifer/data/parcellations.py +0 -1828
- junifer/pipeline/registry.py +0 -177
- junifer/pipeline/tests/test_registry.py +0 -150
- junifer-0.0.5.dev240.dist-info/RECORD +0 -275
- junifer-0.0.5.dev240.dist-info/entry_points.txt +0 -2
- /junifer/{api → cli}/tests/data/gmd_mean.yaml +0 -0
- /junifer/{api → cli}/tests/data/gmd_mean_htcondor.yaml +0 -0
- /junifer/{api → cli}/tests/data/partly_cloudy_agg_mean_tian.yml +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/AutobiographicalMemory_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/CogAC_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/CogAR_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/DMNBuckner_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/Dosenbach2010_MNI_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/Empathy_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/Motor_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/MultiTask_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/PhysioStress_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/Power2011_MNI_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/Power2013_MNI_VOIs.tsv +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/Rew_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/Somatosensory_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/ToM_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/VigAtt_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/WM_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/eMDN_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/eSAD_VOIs.txt +0 -0
- /junifer/data/{VOIs → coordinates/VOIs}/meta/extDMN_VOIs.txt +0 -0
- {junifer-0.0.5.dev240.dist-info → junifer-0.0.6.dist-info/licenses}/AUTHORS.rst +0 -0
- {junifer-0.0.5.dev240.dist-info → junifer-0.0.6.dist-info/licenses}/LICENSE.md +0 -0
- {junifer-0.0.5.dev240.dist-info → junifer-0.0.6.dist-info}/top_level.txt +0 -0
@@ -7,17 +7,18 @@
|
|
7
7
|
|
8
8
|
import atexit
|
9
9
|
import os
|
10
|
-
import shutil
|
11
10
|
import tempfile
|
12
11
|
from pathlib import Path
|
13
|
-
from typing import
|
12
|
+
from typing import Optional, Union
|
14
13
|
|
15
14
|
import datalad
|
16
15
|
import datalad.api as dl
|
17
16
|
from datalad.support.exceptions import IncompleteResultsError
|
18
17
|
from datalad.support.gitrepo import GitRepo
|
19
18
|
|
20
|
-
from ..
|
19
|
+
from ..pipeline import WorkDirManager
|
20
|
+
from ..typing import Element
|
21
|
+
from ..utils import config, logger, raise_error, warn_with_log
|
21
22
|
from .base import BaseDataGrabber
|
22
23
|
|
23
24
|
|
@@ -78,7 +79,8 @@ class DataladDataGrabber(BaseDataGrabber):
|
|
78
79
|
if datadir is None:
|
79
80
|
logger.info("`datadir` is None, creating a temporary directory")
|
80
81
|
# Create temporary directory
|
81
|
-
tmpdir =
|
82
|
+
tmpdir = WorkDirManager().get_tempdir(prefix="datalad")
|
83
|
+
self._tmpdir = tmpdir
|
82
84
|
datadir = tmpdir / "datadir"
|
83
85
|
datadir.mkdir(parents=True, exist_ok=False)
|
84
86
|
logger.info(f"`datadir` set to {datadir}")
|
@@ -104,7 +106,6 @@ class DataladDataGrabber(BaseDataGrabber):
|
|
104
106
|
"Datalad locks set to "
|
105
107
|
f"{datalad.cfg.get('datalad.locations.locks')}"
|
106
108
|
)
|
107
|
-
self._tmpdir = tmpdir
|
108
109
|
atexit.register(self._rmtmpdir)
|
109
110
|
# TODO: uri can be converted to a positional argument
|
110
111
|
if uri is None:
|
@@ -129,7 +130,7 @@ class DataladDataGrabber(BaseDataGrabber):
|
|
129
130
|
"""Remove temporary directory if it exists."""
|
130
131
|
if self._tmpdir.exists():
|
131
132
|
logger.debug("Removing temporary directory")
|
132
|
-
|
133
|
+
WorkDirManager().delete_tempdir(self._tmpdir)
|
133
134
|
|
134
135
|
@property
|
135
136
|
def datadir(self) -> Path:
|
@@ -143,29 +144,51 @@ class DataladDataGrabber(BaseDataGrabber):
|
|
143
144
|
"""
|
144
145
|
return super().datadir / self._rootdir
|
145
146
|
|
146
|
-
def _get_dataset_id_remote(self) -> str:
|
147
|
+
def _get_dataset_id_remote(self) -> tuple[str, bool]:
|
147
148
|
"""Get the dataset ID from the remote.
|
148
149
|
|
149
150
|
Returns
|
150
151
|
-------
|
151
152
|
str
|
152
153
|
The dataset ID.
|
154
|
+
bool
|
155
|
+
Whether the dataset is dirty.
|
156
|
+
|
157
|
+
Raises
|
158
|
+
------
|
159
|
+
ValueError
|
160
|
+
If the dataset ID cannot be obtained from the remote.
|
153
161
|
|
154
162
|
"""
|
155
163
|
remote_id = None
|
164
|
+
is_dirty = False
|
156
165
|
with tempfile.TemporaryDirectory() as tmpdir:
|
157
|
-
|
158
|
-
|
159
|
-
|
166
|
+
if not config.get("datagrabber.skipidcheck", False):
|
167
|
+
logger.debug(f"Querying {self.uri} for dataset ID")
|
168
|
+
repo = GitRepo.clone(
|
169
|
+
self.uri, path=tmpdir, clone_options=["-n", "--depth=1"]
|
170
|
+
)
|
171
|
+
repo.checkout(name=".datalad/config", options=["HEAD"])
|
172
|
+
remote_id = repo.config.get("datalad.dataset.id", None)
|
173
|
+
logger.debug(f"Got remote dataset ID = {remote_id}")
|
174
|
+
|
175
|
+
if not config.get("datagrabber.skipdirtycheck", False):
|
176
|
+
is_dirty = repo.dirty
|
177
|
+
else:
|
178
|
+
logger.debug("Skipping dirty check")
|
179
|
+
is_dirty = False
|
180
|
+
else:
|
181
|
+
logger.debug("Skipping dataset ID check")
|
182
|
+
remote_id = self._dataset.id
|
183
|
+
is_dirty = False
|
184
|
+
logger.debug(
|
185
|
+
f"Remote dataset is {'' if is_dirty else 'not'} dirty"
|
160
186
|
)
|
161
|
-
repo.checkout(name=".datalad/config", options=["HEAD"])
|
162
|
-
remote_id = repo.config.get("datalad.dataset.id", None)
|
163
|
-
logger.debug(f"Got remote dataset ID = {remote_id}")
|
164
187
|
if remote_id is None:
|
165
188
|
raise_error("Could not get dataset ID from remote")
|
166
|
-
return remote_id
|
189
|
+
return remote_id, is_dirty
|
167
190
|
|
168
|
-
def _dataset_get(self, out:
|
191
|
+
def _dataset_get(self, out: dict) -> dict:
|
169
192
|
"""Get the dataset found from the path in ``out``.
|
170
193
|
|
171
194
|
Parameters
|
@@ -178,17 +201,29 @@ class DataladDataGrabber(BaseDataGrabber):
|
|
178
201
|
dict
|
179
202
|
The unmodified input dictionary.
|
180
203
|
|
204
|
+
Raises
|
205
|
+
------
|
206
|
+
datalad.support.exceptions.IncompleteResultsError
|
207
|
+
If there is a datalad-related problem while fetching data.
|
208
|
+
|
181
209
|
"""
|
182
210
|
to_get = []
|
183
211
|
for type_val in out.values():
|
184
|
-
#
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
212
|
+
# Conditional for list dtype vals like Warp
|
213
|
+
if isinstance(type_val, list):
|
214
|
+
for entry in type_val:
|
215
|
+
for k, v in entry.items():
|
216
|
+
if k == "path":
|
217
|
+
to_get.append(v)
|
218
|
+
else:
|
219
|
+
# Iterate to check for nested "types" like mask
|
220
|
+
for k, v in type_val.items():
|
221
|
+
# Add base data type path
|
222
|
+
if k == "path":
|
223
|
+
to_get.append(v)
|
224
|
+
# Add nested data type path
|
225
|
+
if isinstance(v, dict) and "path" in v:
|
226
|
+
to_get.append(v["path"])
|
192
227
|
|
193
228
|
if len(to_get) > 0:
|
194
229
|
logger.debug(f"Getting {len(to_get)} files using datalad:")
|
@@ -223,6 +258,8 @@ class DataladDataGrabber(BaseDataGrabber):
|
|
223
258
|
------
|
224
259
|
ValueError
|
225
260
|
If the dataset is already installed but with a different ID.
|
261
|
+
datalad.support.exceptions.IncompleteResultsError
|
262
|
+
If there is a datalad-related problem while cloning dataset.
|
226
263
|
|
227
264
|
"""
|
228
265
|
isinstalled = dl.Dataset(self._datadir).is_installed()
|
@@ -231,23 +268,23 @@ class DataladDataGrabber(BaseDataGrabber):
|
|
231
268
|
self._got_files = []
|
232
269
|
self._dataset: dl.Dataset = dl.Dataset(self._datadir)
|
233
270
|
|
234
|
-
|
271
|
+
# Check if dataset is already installed with a different ID
|
272
|
+
remote_id, is_dirty = self._get_dataset_id_remote()
|
235
273
|
if remote_id != self._dataset.id:
|
236
274
|
raise_error(
|
237
275
|
"Dataset already installed but with a different "
|
238
276
|
f"ID: {self._dataset.id} (local) != {remote_id} (remote)"
|
239
277
|
)
|
240
278
|
|
241
|
-
#
|
242
|
-
|
243
|
-
if
|
244
|
-
self.datalad_dirty = True
|
279
|
+
# Conditional reporting on dataset dirtiness
|
280
|
+
self.datalad_dirty = is_dirty
|
281
|
+
if self.datalad_dirty:
|
245
282
|
warn_with_log(
|
246
|
-
"At least one file is not clean,
|
247
|
-
"
|
283
|
+
"At least one file is not clean, "
|
284
|
+
f"marking dataset (id: {self._dataset.id}) as dirty."
|
248
285
|
)
|
249
286
|
else:
|
250
|
-
logger.debug("Dataset is clean")
|
287
|
+
logger.debug(f"Dataset (id: {self._dataset.id}) is clean")
|
251
288
|
|
252
289
|
else:
|
253
290
|
logger.debug(f"Installing dataset {self.uri} to {self._datadir}")
|
@@ -276,7 +313,7 @@ class DataladDataGrabber(BaseDataGrabber):
|
|
276
313
|
logger.debug(f"Dropping {f}")
|
277
314
|
self._dataset.drop(f, result_renderer="disabled")
|
278
315
|
|
279
|
-
def __getitem__(self, element:
|
316
|
+
def __getitem__(self, element: Element) -> dict:
|
280
317
|
"""Implement single element indexing in the Datalad database.
|
281
318
|
|
282
319
|
It will first obtain the paths from the parent class and then
|
@@ -284,11 +321,11 @@ class DataladDataGrabber(BaseDataGrabber):
|
|
284
321
|
|
285
322
|
Parameters
|
286
323
|
----------
|
287
|
-
element : str or tuple
|
324
|
+
element : str or tuple of str
|
288
325
|
The element to be indexed. If one string is provided, it is
|
289
326
|
assumed to be a tuple with only one item. If a tuple is provided,
|
290
327
|
each item in the tuple is the value for the replacement string
|
291
|
-
specified in "replacements"
|
328
|
+
specified in ``"replacements"``.
|
292
329
|
|
293
330
|
Returns
|
294
331
|
-------
|
@@ -5,7 +5,7 @@
|
|
5
5
|
|
6
6
|
from itertools import product
|
7
7
|
from pathlib import Path
|
8
|
-
from typing import
|
8
|
+
from typing import Union
|
9
9
|
|
10
10
|
from ..api.decorators import register_datagrabber
|
11
11
|
from ..utils import raise_error
|
@@ -59,11 +59,11 @@ class DMCC13Benchmark(PatternDataladDataGrabber):
|
|
59
59
|
def __init__(
|
60
60
|
self,
|
61
61
|
datadir: Union[str, Path, None] = None,
|
62
|
-
types: Union[str,
|
63
|
-
sessions: Union[str,
|
64
|
-
tasks: Union[str,
|
65
|
-
phase_encodings: Union[str,
|
66
|
-
runs: Union[str,
|
62
|
+
types: Union[str, list[str], None] = None,
|
63
|
+
sessions: Union[str, list[str], None] = None,
|
64
|
+
tasks: Union[str, list[str], None] = None,
|
65
|
+
phase_encodings: Union[str, list[str], None] = None,
|
66
|
+
runs: Union[str, list[str], None] = None,
|
67
67
|
native_t1w: bool = False,
|
68
68
|
) -> None:
|
69
69
|
# Declare all sessions
|
@@ -150,7 +150,7 @@ class DMCC13Benchmark(PatternDataladDataGrabber):
|
|
150
150
|
"mask": {
|
151
151
|
"pattern": (
|
152
152
|
"derivatives/fmriprep-1.3.2/{subject}/{session}/"
|
153
|
-
"
|
153
|
+
"func/{subject}_{session}_task-{task}_acq-mb4"
|
154
154
|
"{phase_encoding}_run-{run}_"
|
155
155
|
"space-MNI152NLin2009cAsym_desc-brain_mask.nii.gz"
|
156
156
|
),
|
@@ -221,15 +221,28 @@ class DMCC13Benchmark(PatternDataladDataGrabber):
|
|
221
221
|
"space": "native",
|
222
222
|
},
|
223
223
|
},
|
224
|
-
"Warp":
|
225
|
-
|
226
|
-
"
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
224
|
+
"Warp": [
|
225
|
+
{
|
226
|
+
"pattern": (
|
227
|
+
"derivatives/fmriprep-1.3.2/{subject}/anat/"
|
228
|
+
"{subject}_from-MNI152NLin2009cAsym_to-T1w_"
|
229
|
+
"mode-image_xfm.h5"
|
230
|
+
),
|
231
|
+
"src": "MNI152NLin2009cAsym",
|
232
|
+
"dst": "native",
|
233
|
+
"warper": "ants",
|
234
|
+
},
|
235
|
+
{
|
236
|
+
"pattern": (
|
237
|
+
"derivatives/fmriprep-1.3.2/{subject}/anat/"
|
238
|
+
"{subject}_from-T1w_to-MNI152NLin2009cAsym_"
|
239
|
+
"mode-image_xfm.h5"
|
240
|
+
),
|
241
|
+
"src": "native",
|
242
|
+
"dst": "MNI152NLin2009cAsym",
|
243
|
+
"warper": "ants",
|
244
|
+
},
|
245
|
+
],
|
233
246
|
}
|
234
247
|
)
|
235
248
|
# Set default types
|
@@ -258,7 +271,7 @@ class DMCC13Benchmark(PatternDataladDataGrabber):
|
|
258
271
|
task: str,
|
259
272
|
phase_encoding: str,
|
260
273
|
run: str,
|
261
|
-
) ->
|
274
|
+
) -> dict:
|
262
275
|
"""Index one element in the dataset.
|
263
276
|
|
264
277
|
Parameters
|
@@ -296,7 +309,7 @@ class DMCC13Benchmark(PatternDataladDataGrabber):
|
|
296
309
|
)
|
297
310
|
return out
|
298
311
|
|
299
|
-
def get_elements(self) ->
|
312
|
+
def get_elements(self) -> list:
|
300
313
|
"""Implement fetching list of subjects in the dataset.
|
301
314
|
|
302
315
|
Returns
|
@@ -3,8 +3,7 @@
|
|
3
3
|
# Authors: Synchon Mandal <s.mandal@fz-juelich.de>
|
4
4
|
# License: AGPL
|
5
5
|
|
6
|
-
|
7
|
-
from .datalad_hcp1200 import DataladHCP1200
|
6
|
+
import lazy_loader as lazy
|
8
7
|
|
9
8
|
|
10
|
-
__all__ =
|
9
|
+
__getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__)
|
@@ -6,7 +6,7 @@
|
|
6
6
|
# License: AGPL
|
7
7
|
|
8
8
|
from pathlib import Path
|
9
|
-
from typing import
|
9
|
+
from typing import Union
|
10
10
|
|
11
11
|
from junifer.datagrabber.datalad_base import DataladDataGrabber
|
12
12
|
|
@@ -50,8 +50,8 @@ class DataladHCP1200(DataladDataGrabber, HCP1200):
|
|
50
50
|
def __init__(
|
51
51
|
self,
|
52
52
|
datadir: Union[str, Path, None] = None,
|
53
|
-
tasks: Union[str,
|
54
|
-
phase_encodings: Union[str,
|
53
|
+
tasks: Union[str, list[str], None] = None,
|
54
|
+
phase_encodings: Union[str, list[str], None] = None,
|
55
55
|
ica_fix: bool = False,
|
56
56
|
) -> None:
|
57
57
|
uri = (
|
@@ -7,7 +7,7 @@
|
|
7
7
|
|
8
8
|
from itertools import product
|
9
9
|
from pathlib import Path
|
10
|
-
from typing import
|
10
|
+
from typing import Union
|
11
11
|
|
12
12
|
from ...api.decorators import register_datagrabber
|
13
13
|
from ...utils import raise_error
|
@@ -48,8 +48,8 @@ class HCP1200(PatternDataGrabber):
|
|
48
48
|
def __init__(
|
49
49
|
self,
|
50
50
|
datadir: Union[str, Path],
|
51
|
-
tasks: Union[str,
|
52
|
-
phase_encodings: Union[str,
|
51
|
+
tasks: Union[str, list[str], None] = None,
|
52
|
+
phase_encodings: Union[str, list[str], None] = None,
|
53
53
|
ica_fix: bool = False,
|
54
54
|
) -> None:
|
55
55
|
# All tasks
|
@@ -66,10 +66,10 @@ class HCP1200(PatternDataGrabber):
|
|
66
66
|
]
|
67
67
|
# Set default tasks
|
68
68
|
if tasks is None:
|
69
|
-
self.tasks:
|
69
|
+
self.tasks: list[str] = all_tasks
|
70
70
|
# Convert single task into list
|
71
71
|
else:
|
72
|
-
if not isinstance(tasks,
|
72
|
+
if not isinstance(tasks, list):
|
73
73
|
tasks = [tasks]
|
74
74
|
# Check for invalid task(s)
|
75
75
|
for task in tasks:
|
@@ -78,7 +78,7 @@ class HCP1200(PatternDataGrabber):
|
|
78
78
|
f"'{task}' is not a valid HCP-YA fMRI task input. "
|
79
79
|
f"Valid task values can be any or all of {all_tasks}."
|
80
80
|
)
|
81
|
-
self.tasks:
|
81
|
+
self.tasks: list[str] = tasks
|
82
82
|
|
83
83
|
# All phase encodings
|
84
84
|
all_phase_encodings = ["LR", "RL"]
|
@@ -122,13 +122,24 @@ class HCP1200(PatternDataGrabber):
|
|
122
122
|
"pattern": "{subject}/T1w/T1w_acpc_dc_restore.nii.gz",
|
123
123
|
"space": "native",
|
124
124
|
},
|
125
|
-
"Warp":
|
126
|
-
|
127
|
-
"
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
125
|
+
"Warp": [
|
126
|
+
{
|
127
|
+
"pattern": (
|
128
|
+
"{subject}/MNINonLinear/xfms/standard2acpc_dc.nii.gz"
|
129
|
+
),
|
130
|
+
"src": "MNI152NLin6Asym",
|
131
|
+
"dst": "native",
|
132
|
+
"warper": "fsl",
|
133
|
+
},
|
134
|
+
{
|
135
|
+
"pattern": (
|
136
|
+
"{subject}/MNINonLinear/xfms/acpc_dc2standard.nii.gz"
|
137
|
+
),
|
138
|
+
"src": "native",
|
139
|
+
"dst": "MNI152NLin6Asym",
|
140
|
+
"warper": "fsl",
|
141
|
+
},
|
142
|
+
],
|
132
143
|
}
|
133
144
|
# The replacements
|
134
145
|
replacements = ["subject", "task", "phase_encoding"]
|
@@ -139,7 +150,7 @@ class HCP1200(PatternDataGrabber):
|
|
139
150
|
replacements=replacements,
|
140
151
|
)
|
141
152
|
|
142
|
-
def get_item(self, subject: str, task: str, phase_encoding: str) ->
|
153
|
+
def get_item(self, subject: str, task: str, phase_encoding: str) -> dict:
|
143
154
|
"""Implement single element indexing in the database.
|
144
155
|
|
145
156
|
Parameters
|
@@ -169,7 +180,7 @@ class HCP1200(PatternDataGrabber):
|
|
169
180
|
subject=subject, task=new_task, phase_encoding=phase_encoding
|
170
181
|
)
|
171
182
|
|
172
|
-
def get_elements(self) ->
|
183
|
+
def get_elements(self) -> list:
|
173
184
|
"""Implement fetching list of elements in the dataset.
|
174
185
|
|
175
186
|
Returns
|
File without changes
|
@@ -3,7 +3,11 @@
|
|
3
3
|
# Authors: Synchon Mandal <s.mandal@fz-juelich.de>
|
4
4
|
# License: AGPL
|
5
5
|
|
6
|
-
|
6
|
+
import shutil
|
7
|
+
import tempfile
|
8
|
+
from collections.abc import Iterable
|
9
|
+
from pathlib import Path
|
10
|
+
from typing import Optional
|
7
11
|
|
8
12
|
import pytest
|
9
13
|
|
@@ -17,7 +21,8 @@ URI = "https://gin.g-node.org/juaml/datalad-example-hcp1200"
|
|
17
21
|
@pytest.fixture(scope="module")
|
18
22
|
def hcpdg() -> Iterable[DataladHCP1200]:
|
19
23
|
"""Return a HCP1200 DataGrabber."""
|
20
|
-
|
24
|
+
tmpdir = Path(tempfile.gettempdir())
|
25
|
+
dg = DataladHCP1200(datadir=tmpdir / "datadir")
|
21
26
|
# Set URI to Gin
|
22
27
|
dg.uri = URI
|
23
28
|
# Set correct root directory
|
@@ -26,6 +31,7 @@ def hcpdg() -> Iterable[DataladHCP1200]:
|
|
26
31
|
for t_elem in dg.get_elements():
|
27
32
|
dg[t_elem]
|
28
33
|
yield dg
|
34
|
+
shutil.rmtree(tmpdir / "datadir", ignore_errors=True)
|
29
35
|
|
30
36
|
|
31
37
|
@pytest.mark.parametrize(
|
junifer/datagrabber/multiple.py
CHANGED
@@ -5,9 +5,10 @@
|
|
5
5
|
# Synchon Mandal <s.mandal@fz-juelich.de>
|
6
6
|
# License: AGPL
|
7
7
|
|
8
|
-
from typing import
|
8
|
+
from typing import Union
|
9
9
|
|
10
10
|
from ..api.decorators import register_datagrabber
|
11
|
+
from ..typing import DataGrabberLike
|
11
12
|
from ..utils import deep_update, raise_error
|
12
13
|
from .base import BaseDataGrabber
|
13
14
|
|
@@ -37,7 +38,7 @@ class MultipleDataGrabber(BaseDataGrabber):
|
|
37
38
|
|
38
39
|
"""
|
39
40
|
|
40
|
-
def __init__(self, datagrabbers:
|
41
|
+
def __init__(self, datagrabbers: list[DataGrabberLike], **kwargs) -> None:
|
41
42
|
# Check datagrabbers consistency
|
42
43
|
# Check for same element keys
|
43
44
|
first_keys = datagrabbers[0].get_element_keys()
|
@@ -78,7 +79,7 @@ class MultipleDataGrabber(BaseDataGrabber):
|
|
78
79
|
)
|
79
80
|
self._datagrabbers = datagrabbers
|
80
81
|
|
81
|
-
def __getitem__(self, element: Union[str,
|
82
|
+
def __getitem__(self, element: Union[str, tuple]) -> dict:
|
82
83
|
"""Implement indexing.
|
83
84
|
|
84
85
|
Parameters
|
@@ -110,8 +111,12 @@ class MultipleDataGrabber(BaseDataGrabber):
|
|
110
111
|
|
111
112
|
# Update all the metas again
|
112
113
|
for kind in out:
|
113
|
-
|
114
|
-
|
114
|
+
to_update = out[kind]
|
115
|
+
if not isinstance(to_update, list):
|
116
|
+
to_update = [to_update]
|
117
|
+
for t_kind in to_update:
|
118
|
+
self.update_meta(t_kind, "datagrabber")
|
119
|
+
t_kind["meta"]["datagrabber"]["datagrabbers"] = metas
|
115
120
|
return out
|
116
121
|
|
117
122
|
def __enter__(self) -> "MultipleDataGrabber":
|
@@ -126,7 +131,7 @@ class MultipleDataGrabber(BaseDataGrabber):
|
|
126
131
|
dg.__exit__(exc_type, exc_value, exc_traceback)
|
127
132
|
|
128
133
|
# TODO: return type should be List[List[str]], but base type is List[str]
|
129
|
-
def get_types(self) ->
|
134
|
+
def get_types(self) -> list[str]:
|
130
135
|
"""Get types.
|
131
136
|
|
132
137
|
Returns
|
@@ -138,7 +143,7 @@ class MultipleDataGrabber(BaseDataGrabber):
|
|
138
143
|
types = [x for dg in self._datagrabbers for x in dg.get_types()]
|
139
144
|
return types
|
140
145
|
|
141
|
-
def get_element_keys(self) ->
|
146
|
+
def get_element_keys(self) -> list[str]:
|
142
147
|
"""Get element keys.
|
143
148
|
|
144
149
|
For each item in the ``element`` tuple passed to ``__getitem__()``,
|
@@ -152,7 +157,7 @@ class MultipleDataGrabber(BaseDataGrabber):
|
|
152
157
|
"""
|
153
158
|
return self._datagrabbers[0].get_element_keys()
|
154
159
|
|
155
|
-
def get_elements(self) ->
|
160
|
+
def get_elements(self) -> list:
|
156
161
|
"""Get elements.
|
157
162
|
|
158
163
|
Returns
|
@@ -170,7 +175,7 @@ class MultipleDataGrabber(BaseDataGrabber):
|
|
170
175
|
elements.intersection_update(s)
|
171
176
|
return list(elements)
|
172
177
|
|
173
|
-
def get_item(self, **_:
|
178
|
+
def get_item(self, **_: dict) -> dict[str, dict]:
|
174
179
|
"""Get the specified item from the dataset.
|
175
180
|
|
176
181
|
Parameters
|