junifer 0.0.7.dev332__py3-none-any.whl → 0.0.8__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/_version.py +9 -19
- junifer/api/__init__.pyi +17 -2
- junifer/api/functions.py +222 -39
- junifer/api/queue_context/__init__.pyi +11 -3
- junifer/api/queue_context/gnu_parallel_local_adapter.py +81 -120
- junifer/api/queue_context/htcondor_adapter.py +118 -181
- junifer/api/queue_context/queue_context_adapter.py +51 -7
- junifer/api/queue_context/tests/test_gnu_parallel_local_adapter.py +10 -35
- junifer/api/queue_context/tests/test_htcondor_adapter.py +13 -50
- junifer/api/res/fsl/run_fsl_docker.sh +4 -0
- junifer/api/tests/test_functions.py +863 -36
- junifer/cli/__init__.py +1 -7
- junifer/cli/cli.py +41 -22
- junifer/cli/parser.py +23 -147
- junifer/cli/tests/data/gmd_mean.yaml +6 -6
- junifer/cli/tests/data/gmd_mean_htcondor.yaml +6 -5
- junifer/cli/tests/data/partly_cloudy_agg_mean_tian.yml +1 -0
- junifer/cli/tests/test_cli.py +120 -4
- junifer/cli/tests/test_cli_utils.py +23 -6
- junifer/cli/utils.py +14 -9
- junifer/configs/__init__.py +5 -0
- junifer/configs/__init__.pyi +0 -0
- junifer/configs/juseless/datagrabbers/__init__.pyi +4 -2
- junifer/configs/juseless/datagrabbers/aomic_id1000_vbm.py +18 -24
- junifer/configs/juseless/datagrabbers/camcan_vbm.py +20 -27
- junifer/configs/juseless/datagrabbers/ixi_vbm.py +44 -52
- junifer/configs/juseless/datagrabbers/tests/test_ixi_vbm.py +0 -7
- junifer/configs/juseless/datagrabbers/tests/test_ucla.py +2 -19
- junifer/configs/juseless/datagrabbers/ucla.py +111 -104
- junifer/configs/juseless/datagrabbers/ukb_vbm.py +19 -25
- junifer/configs/py.typed +0 -0
- junifer/conftest.py +63 -24
- junifer/data/_dispatch.py +9 -19
- junifer/data/coordinates/_ants_coordinates_warper.py +4 -1
- junifer/data/coordinates/_coordinates.py +51 -6
- junifer/data/coordinates/_fsl_coordinates_warper.py +4 -1
- junifer/data/coordinates/tests/test_coordinates.py +15 -3
- junifer/data/coordinates/tests/test_coordinates_names.py +37 -0
- junifer/data/maps/_ants_maps_warper.py +18 -12
- junifer/data/maps/_fsl_maps_warper.py +7 -3
- junifer/data/maps/_maps.py +12 -8
- junifer/data/maps/tests/test_maps.py +13 -21
- junifer/data/masks/_ants_mask_warper.py +18 -12
- junifer/data/masks/_fsl_mask_warper.py +7 -3
- junifer/data/masks/_masks.py +15 -12
- junifer/data/masks/tests/test_masks.py +20 -17
- junifer/data/parcellations/_ants_parcellation_warper.py +18 -12
- junifer/data/parcellations/_fsl_parcellation_warper.py +7 -5
- junifer/data/parcellations/_parcellations.py +125 -91
- junifer/data/parcellations/tests/test_parcellations.py +122 -1
- junifer/data/template_spaces.py +117 -50
- junifer/data/tests/test_template_spaces.py +10 -7
- junifer/data/utils.py +10 -8
- junifer/datagrabber/__init__.pyi +38 -5
- junifer/datagrabber/aomic/__init__.pyi +8 -1
- junifer/datagrabber/aomic/_types.py +22 -0
- junifer/datagrabber/aomic/id1000.py +193 -183
- junifer/datagrabber/aomic/piop1.py +215 -259
- junifer/datagrabber/aomic/piop2.py +211 -244
- junifer/datagrabber/aomic/tests/test_id1000.py +70 -53
- junifer/datagrabber/aomic/tests/test_piop1.py +98 -102
- junifer/datagrabber/aomic/tests/test_piop2.py +88 -85
- junifer/datagrabber/base.py +253 -79
- junifer/datagrabber/datalad_base.py +127 -76
- junifer/datagrabber/dmcc13_benchmark.py +204 -289
- junifer/datagrabber/hcp1200/__init__.pyi +7 -2
- junifer/datagrabber/hcp1200/datalad_hcp1200.py +61 -40
- junifer/datagrabber/hcp1200/hcp1200.py +151 -164
- junifer/datagrabber/hcp1200/tests/test_hcp1200.py +116 -128
- junifer/datagrabber/multiple.py +183 -63
- junifer/datagrabber/pattern.py +358 -227
- junifer/datagrabber/pattern_datalad.py +84 -124
- junifer/datagrabber/pattern_validation_mixin.py +22 -50
- junifer/datagrabber/tests/test_base.py +17 -4
- junifer/datagrabber/tests/test_datalad_base.py +20 -27
- junifer/datagrabber/tests/test_dmcc13_benchmark.py +110 -122
- junifer/datagrabber/tests/test_multiple.py +293 -31
- junifer/datagrabber/tests/test_pattern.py +577 -18
- junifer/datagrabber/tests/test_pattern_datalad.py +177 -107
- junifer/datagrabber/tests/test_pattern_validation_mixin.py +9 -51
- junifer/datareader/default.py +8 -5
- junifer/datareader/tests/test_default_reader.py +1 -1
- junifer/external/BrainPrint/.codecov.yml +2 -0
- junifer/external/BrainPrint/.codespellignore +2 -0
- junifer/external/BrainPrint/.github/ISSUE_TEMPLATE/bug-report.md +45 -0
- junifer/external/BrainPrint/.github/ISSUE_TEMPLATE/documentation.md +12 -0
- junifer/external/BrainPrint/.github/ISSUE_TEMPLATE/feature-request.md +24 -0
- junifer/external/BrainPrint/.github/ISSUE_TEMPLATE/questions-help-support.md +28 -0
- junifer/external/BrainPrint/.github/dependabot.yml +6 -0
- junifer/external/BrainPrint/.github/workflows/build.yml +53 -0
- junifer/external/BrainPrint/.github/workflows/code-style.yml +44 -0
- junifer/external/BrainPrint/.github/workflows/doc.yml +65 -0
- junifer/external/BrainPrint/.github/workflows/publish.yml +31 -0
- junifer/external/BrainPrint/.github/workflows/pytest.yml +54 -0
- junifer/external/BrainPrint/.gitignore +123 -0
- junifer/external/BrainPrint/LICENSE +21 -0
- junifer/external/BrainPrint/README.md +108 -0
- junifer/external/BrainPrint/brainprint/cli/__init__.py +11 -0
- junifer/external/BrainPrint/brainprint/cli/help_text.py +169 -0
- junifer/external/BrainPrint/brainprint/cli/parser.py +150 -0
- junifer/external/BrainPrint/brainprint/cli/utils.py +14 -0
- junifer/external/BrainPrint/brainprint/commands/__init__.py +0 -0
- junifer/external/BrainPrint/brainprint/commands/sys_info.py +18 -0
- junifer/external/BrainPrint/brainprint/utils/tests/__init__.py +0 -0
- junifer/external/BrainPrint/brainprint/utils/tests/test_config.py +33 -0
- junifer/external/BrainPrint/doc/Makefile +20 -0
- junifer/external/BrainPrint/doc/_static/.gitkeep +0 -0
- junifer/external/BrainPrint/doc/_templates/autosummary/class.rst +10 -0
- junifer/external/BrainPrint/doc/_templates/autosummary/function.rst +8 -0
- junifer/external/BrainPrint/doc/_templates/autosummary/module.rst +6 -0
- junifer/external/BrainPrint/doc/api/index.rst +11 -0
- junifer/external/BrainPrint/doc/conf.py +272 -0
- junifer/external/BrainPrint/doc/index.rst +140 -0
- junifer/external/BrainPrint/doc/links.inc +36 -0
- junifer/external/BrainPrint/doc/make.bat +35 -0
- junifer/external/BrainPrint/doc/references.bib +23 -0
- junifer/external/BrainPrint/pyproject.toml +170 -0
- junifer/external/BrainPrint/setup.py +3 -0
- junifer/external/__init__.py +5 -0
- junifer/external/__init__.pyi +0 -0
- junifer/external/nilearn/junifer_connectivity_measure.py +95 -39
- junifer/external/nilearn/junifer_nifti_spheres_masker.py +226 -67
- junifer/external/nilearn/tests/test_junifer_connectivity_measure.py +39 -27
- junifer/external/nilearn/tests/test_junifer_nifti_spheres_masker.py +231 -21
- junifer/external/py.typed +0 -0
- junifer/markers/__init__.pyi +6 -3
- junifer/markers/base.py +126 -76
- junifer/markers/brainprint.py +30 -39
- junifer/markers/complexity/__init__.py +20 -3
- junifer/markers/complexity/complexity_base.py +40 -41
- junifer/markers/complexity/hurst_exponent.py +22 -35
- junifer/markers/complexity/multiscale_entropy_auc.py +53 -41
- junifer/markers/complexity/perm_entropy.py +22 -36
- junifer/markers/complexity/range_entropy.py +22 -35
- junifer/markers/complexity/range_entropy_auc.py +27 -36
- junifer/markers/complexity/sample_entropy.py +22 -36
- junifer/markers/complexity/tests/test_complexity_registry.py +48 -0
- junifer/markers/complexity/tests/test_hurst_exponent.py +47 -36
- junifer/markers/complexity/tests/test_multiscale_entropy_auc.py +50 -36
- junifer/markers/complexity/tests/test_perm_entropy.py +48 -36
- junifer/markers/complexity/tests/test_range_entropy.py +47 -36
- junifer/markers/complexity/tests/test_range_entropy_auc.py +47 -36
- junifer/markers/complexity/tests/test_sample_entropy.py +48 -36
- junifer/markers/complexity/tests/test_weighted_perm_entropy.py +50 -36
- junifer/markers/complexity/weighted_perm_entropy.py +22 -36
- junifer/markers/ets_rss.py +35 -31
- junifer/markers/falff/__init__.pyi +7 -1
- junifer/markers/falff/_afni_falff.py +22 -9
- junifer/markers/falff/_junifer_falff.py +47 -31
- junifer/markers/falff/falff_base.py +80 -60
- junifer/markers/falff/falff_maps.py +17 -41
- junifer/markers/falff/falff_parcels.py +26 -51
- junifer/markers/falff/falff_spheres.py +34 -61
- junifer/markers/falff/tests/test_falff_maps.py +20 -23
- junifer/markers/falff/tests/test_falff_mask.py +99 -0
- junifer/markers/falff/tests/test_falff_parcels.py +14 -10
- junifer/markers/falff/tests/test_falff_spheres.py +14 -10
- junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +32 -34
- junifer/markers/functional_connectivity/edge_functional_connectivity_maps.py +12 -25
- junifer/markers/functional_connectivity/edge_functional_connectivity_parcels.py +19 -34
- junifer/markers/functional_connectivity/edge_functional_connectivity_spheres.py +24 -44
- junifer/markers/functional_connectivity/functional_connectivity_base.py +50 -40
- junifer/markers/functional_connectivity/functional_connectivity_maps.py +12 -25
- junifer/markers/functional_connectivity/functional_connectivity_parcels.py +19 -34
- junifer/markers/functional_connectivity/functional_connectivity_spheres.py +24 -45
- junifer/markers/functional_connectivity/tests/test_crossparcellation_functional_connectivity.py +21 -22
- junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_maps.py +8 -7
- junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_parcels.py +8 -4
- junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_spheres.py +8 -4
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_maps.py +8 -7
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_parcels.py +9 -5
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_spheres.py +8 -12
- junifer/markers/maps_aggregation.py +77 -55
- junifer/markers/parcel_aggregation.py +91 -70
- junifer/markers/reho/__init__.pyi +7 -1
- junifer/markers/reho/_afni_reho.py +23 -14
- junifer/markers/reho/_junifer_reho.py +112 -123
- junifer/markers/reho/reho_base.py +115 -37
- junifer/markers/reho/reho_maps.py +18 -32
- junifer/markers/reho/reho_parcels.py +26 -41
- junifer/markers/reho/reho_spheres.py +33 -54
- junifer/markers/reho/tests/test_junifer_reho.py +178 -0
- junifer/markers/reho/tests/test_reho_maps.py +27 -25
- junifer/markers/reho/tests/test_reho_parcels.py +28 -22
- junifer/markers/reho/tests/test_reho_spheres.py +16 -12
- junifer/markers/sphere_aggregation.py +88 -72
- junifer/markers/temporal_snr/temporal_snr_base.py +32 -30
- junifer/markers/temporal_snr/temporal_snr_maps.py +9 -18
- junifer/markers/temporal_snr/temporal_snr_parcels.py +19 -27
- junifer/markers/temporal_snr/temporal_snr_spheres.py +27 -41
- junifer/markers/temporal_snr/tests/test_temporal_snr_base.py +2 -2
- junifer/markers/temporal_snr/tests/test_temporal_snr_maps.py +17 -22
- junifer/markers/temporal_snr/tests/test_temporal_snr_parcels.py +11 -3
- junifer/markers/temporal_snr/tests/test_temporal_snr_spheres.py +9 -9
- junifer/markers/tests/test_brainprint.py +10 -9
- junifer/markers/tests/test_ets_rss.py +7 -3
- junifer/markers/tests/test_lost_regions.py +279 -0
- junifer/markers/tests/test_maps_aggregation.py +67 -114
- junifer/markers/tests/test_marker_utils.py +40 -1
- junifer/markers/tests/test_markers_base.py +275 -6
- junifer/markers/tests/test_parcel_aggregation.py +91 -53
- junifer/markers/tests/test_sphere_aggregation.py +53 -47
- junifer/markers/utils.py +267 -5
- junifer/onthefly/__init__.py +2 -3
- junifer/onthefly/__init__.pyi +4 -0
- junifer/onthefly/_brainprint.py +3 -5
- junifer/onthefly/py.typed +0 -0
- junifer/onthefly/read_transform.py +11 -9
- junifer/onthefly/tests/test_read_transform.py +7 -7
- junifer/pipeline/__init__.pyi +4 -2
- junifer/pipeline/marker_collection.py +14 -10
- junifer/pipeline/pipeline_component_registry.py +25 -6
- junifer/pipeline/pipeline_step_mixin.py +5 -12
- junifer/pipeline/tests/test_data_object_dumper.py +10 -10
- junifer/pipeline/tests/test_marker_collection.py +145 -168
- junifer/pipeline/tests/test_pipeline_component_registry.py +52 -8
- junifer/pipeline/tests/test_pipeline_step_mixin.py +12 -26
- junifer/pipeline/tests/test_update_meta_mixin.py +4 -5
- junifer/pipeline/tests/test_workdir_manager.py +39 -0
- junifer/pipeline/update_meta_mixin.py +13 -10
- junifer/pipeline/utils.py +22 -17
- junifer/pipeline/workdir_manager.py +41 -32
- junifer/preprocess/__init__.pyi +9 -4
- junifer/preprocess/_temporal_filter.py +34 -33
- junifer/preprocess/_temporal_slicer.py +17 -30
- junifer/preprocess/base.py +99 -55
- junifer/preprocess/confounds/__init__.pyi +10 -2
- junifer/preprocess/confounds/fmriprep_confound_remover.py +87 -109
- junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py +64 -45
- junifer/preprocess/smoothing/__init__.pyi +2 -2
- junifer/preprocess/smoothing/_afni_smoothing.py +8 -7
- junifer/preprocess/smoothing/_fsl_smoothing.py +6 -4
- junifer/preprocess/smoothing/_nilearn_smoothing.py +7 -5
- junifer/preprocess/smoothing/smoothing.py +59 -40
- junifer/preprocess/smoothing/tests/test_smoothing.py +28 -8
- junifer/preprocess/tests/test_preprocess_base.py +17 -9
- junifer/preprocess/tests/test_temporal_filter.py +37 -16
- junifer/preprocess/tests/test_temporal_slicer.py +12 -12
- junifer/preprocess/warping/__init__.pyi +2 -2
- junifer/preprocess/warping/_ants_warper.py +56 -40
- junifer/preprocess/warping/_fsl_warper.py +49 -36
- junifer/preprocess/warping/_utils.py +106 -0
- junifer/preprocess/warping/space_warper.py +99 -98
- junifer/preprocess/warping/tests/test_space_warper.py +46 -41
- junifer/preprocess/warping/tests/test_warping_utils.py +163 -0
- junifer/stats.py +46 -34
- junifer/storage/__init__.pyi +8 -4
- junifer/storage/base.py +129 -64
- junifer/storage/hdf5.py +307 -199
- junifer/storage/pandas_base.py +46 -24
- junifer/storage/sqlite.py +99 -62
- junifer/storage/tests/data/collected_h5io_fork.hdf5 +0 -0
- junifer/storage/tests/test_hdf5.py +147 -12
- junifer/storage/tests/test_repeated_storage.py +293 -0
- junifer/storage/tests/test_sqlite.py +9 -20
- junifer/storage/tests/test_storage_base.py +18 -21
- junifer/storage/tests/test_utils.py +83 -22
- junifer/storage/utils.py +58 -38
- junifer/testing/__init__.pyi +2 -2
- junifer/testing/datagrabbers.py +480 -44
- junifer/testing/registry.py +12 -0
- junifer/testing/tests/test_adhdtesting_datagrabber.py +24 -0
- junifer/testing/tests/test_oasisvmbtesting_datagrabber.py +5 -0
- junifer/testing/tests/test_partlycloudytesting_datagrabber.py +52 -0
- junifer/testing/tests/test_spmauditory_datagrabber.py +16 -0
- junifer/testing/tests/test_testing_registry.py +31 -0
- junifer/testing/tests/test_testing_utils.py +35 -0
- junifer/testing/tests/test_uclacnpvbmtesting_datagrabber.py +81 -0
- junifer/testing/utils.py +33 -1
- junifer/tests/test_stats.py +1 -5
- junifer/typing/__init__.pyi +2 -0
- junifer/typing/_typing.py +34 -19
- junifer/typing/py.typed +0 -0
- junifer/utils/__init__.pyi +10 -1
- junifer/utils/_config.py +1 -2
- junifer/utils/helpers.py +68 -2
- junifer/utils/logging.py +31 -7
- junifer/utils/tests/test_helpers.py +36 -1
- {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/METADATA +43 -35
- junifer-0.0.8.dist-info/RECORD +402 -0
- {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/WHEEL +1 -1
- junifer/cli/tests/test_parser.py +0 -280
- junifer/external/h5io/h5io/__init__.py +0 -15
- junifer/external/h5io/h5io/_h5io.py +0 -767
- junifer/external/h5io/h5io/_version.py +0 -1
- junifer/external/h5io/h5io/chunked_array.py +0 -94
- junifer/external/h5io/h5io/chunked_list.py +0 -65
- junifer/markers/complexity/__init__.pyi +0 -17
- junifer-0.0.7.dev332.dist-info/RECORD +0 -353
- {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/entry_points.txt +0 -0
- {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/licenses/AUTHORS.rst +0 -0
- {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/licenses/LICENSE.md +0 -0
- {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/top_level.txt +0 -0
|
@@ -9,22 +9,44 @@ import atexit
|
|
|
9
9
|
import os
|
|
10
10
|
import tempfile
|
|
11
11
|
from pathlib import Path
|
|
12
|
-
from typing import
|
|
12
|
+
from typing import Any, NoReturn
|
|
13
13
|
|
|
14
14
|
import datalad
|
|
15
15
|
import datalad.api as dl
|
|
16
16
|
from datalad.support.exceptions import IncompleteResultsError
|
|
17
17
|
from datalad.support.gitrepo import GitRepo
|
|
18
|
+
from pydantic import AnyUrl, Field, field_validator
|
|
18
19
|
|
|
20
|
+
from ..api.decorators import register_datagrabber
|
|
19
21
|
from ..pipeline import WorkDirManager
|
|
20
22
|
from ..typing import Element
|
|
21
|
-
from ..utils import config,
|
|
22
|
-
from .base import BaseDataGrabber
|
|
23
|
+
from ..utils import config, raise_error, warn_with_log
|
|
24
|
+
from .base import BaseDataGrabber, logger
|
|
23
25
|
|
|
24
26
|
|
|
25
27
|
__all__ = ["DataladDataGrabber"]
|
|
26
28
|
|
|
27
29
|
|
|
30
|
+
def _create_datadir() -> Path:
|
|
31
|
+
"""Create a temporary directory for datalad dataset."""
|
|
32
|
+
datadir = WorkDirManager().get_tempdir(
|
|
33
|
+
prefix="datalad", suffix="juniferauto"
|
|
34
|
+
)
|
|
35
|
+
logger.info(
|
|
36
|
+
"Created a temporary directory for datalad dataset at: "
|
|
37
|
+
f"{datadir.resolve()!s}"
|
|
38
|
+
)
|
|
39
|
+
return datadir
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def _remove_datadir(datadir: Path) -> None:
|
|
43
|
+
"""Remove temporary directory if it exists."""
|
|
44
|
+
if datadir.exists():
|
|
45
|
+
logger.debug(f"Removing temporary directory at: {datadir.resolve()!s}")
|
|
46
|
+
WorkDirManager().delete_tempdir(datadir)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@register_datagrabber
|
|
28
50
|
class DataladDataGrabber(BaseDataGrabber):
|
|
29
51
|
"""Abstract base class for datalad-based data fetching.
|
|
30
52
|
|
|
@@ -32,17 +54,15 @@ class DataladDataGrabber(BaseDataGrabber):
|
|
|
32
54
|
|
|
33
55
|
Parameters
|
|
34
56
|
----------
|
|
35
|
-
|
|
57
|
+
uri : pydantic.AnyUrl
|
|
58
|
+
URI of the datalad sibling.
|
|
59
|
+
rootdir : pathlib.Path, optional
|
|
36
60
|
The path within the datalad dataset to the root directory
|
|
37
|
-
(default ".").
|
|
38
|
-
datadir :
|
|
39
|
-
That
|
|
40
|
-
the datalad dataset will be cloned into a temporary
|
|
41
|
-
|
|
42
|
-
uri : str or None, optional
|
|
43
|
-
URI of the datalad sibling (default None).
|
|
44
|
-
**kwargs
|
|
45
|
-
Keyword arguments passed to superclass.
|
|
61
|
+
(default Path(".")).
|
|
62
|
+
datadir : pathlib.Path, optional
|
|
63
|
+
That path where the datalad dataset will be cloned.
|
|
64
|
+
If not specified, the datalad dataset will be cloned into a temporary
|
|
65
|
+
directory.
|
|
46
66
|
|
|
47
67
|
Methods
|
|
48
68
|
-------
|
|
@@ -67,24 +87,62 @@ class DataladDataGrabber(BaseDataGrabber):
|
|
|
67
87
|
This class is intended to be used as a superclass of a subclass
|
|
68
88
|
with multiple inheritance.
|
|
69
89
|
|
|
90
|
+
If the ``datadir`` is specified and has the stem prefix as ``"datalad"``
|
|
91
|
+
and the stem suffix as ``"juniferauto"``, it will be automatically
|
|
92
|
+
deleted after use.
|
|
93
|
+
|
|
70
94
|
"""
|
|
71
95
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
96
|
+
uri: AnyUrl = Field(frozen=True)
|
|
97
|
+
rootdir: Path = Field(frozen=True, default=Path("."))
|
|
98
|
+
datadir: Path = Field(default_factory=lambda: _create_datadir())
|
|
99
|
+
_repodir: Path = Path(".")
|
|
100
|
+
# Flag to indicate if the dataset was cloned before and it might be
|
|
101
|
+
# dirty
|
|
102
|
+
datalad_dirty: bool = False
|
|
103
|
+
datalad_commit_id: str | None = None
|
|
104
|
+
datalad_id: str | None = None
|
|
105
|
+
_dataset: dl.Dataset | None = None
|
|
106
|
+
_got_files: list[str] = [] # noqa: RUF012
|
|
107
|
+
_was_cloned: bool = False
|
|
108
|
+
|
|
109
|
+
@field_validator("datadir", mode="after")
|
|
110
|
+
@classmethod
|
|
111
|
+
def warn_existing_datalad_autodir(cls, value: Path) -> Path:
|
|
112
|
+
"""Warn if existing datalad autodir exists."""
|
|
113
|
+
if value.stem.startswith("datalad") and value.stem.endswith(
|
|
114
|
+
"juniferauto"
|
|
115
|
+
):
|
|
116
|
+
warn_with_log(
|
|
117
|
+
f"{value.resolve()!s} already exists and will reuse assets "
|
|
118
|
+
"from previous run."
|
|
119
|
+
)
|
|
120
|
+
return value
|
|
121
|
+
|
|
122
|
+
@field_validator("datalad_dirty", mode="before")
|
|
123
|
+
@classmethod
|
|
124
|
+
def disable_tag(cls, value: Any) -> NoReturn:
|
|
125
|
+
"""Disable setting datalad_dirty directly."""
|
|
126
|
+
raise_error(
|
|
127
|
+
msg="datalad_dirty cannot be set directly",
|
|
128
|
+
klass=ValueError,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
def validate_datagrabber_params(self) -> None:
|
|
132
|
+
"""Run extra logical validation for datagrabber."""
|
|
133
|
+
logger.debug("Initializing DataladDataGrabber")
|
|
134
|
+
logger.debug(f"\turi = {self.uri}")
|
|
135
|
+
logger.debug(f"\trootdir = {self.rootdir}")
|
|
136
|
+
if self.datadir.stem.startswith(
|
|
137
|
+
"datalad"
|
|
138
|
+
) and self.datadir.stem.endswith("juniferauto"):
|
|
139
|
+
self._repodir = self.datadir / "dataset"
|
|
140
|
+
self._repodir.mkdir(parents=True, exist_ok=False)
|
|
141
|
+
logger.info(
|
|
142
|
+
"Datalad dataset installation path set to: "
|
|
143
|
+
f"{self._repodir.resolve()!s}"
|
|
144
|
+
)
|
|
145
|
+
cache_dir = self.datadir / ".datalad_cache"
|
|
88
146
|
sockets_dir = cache_dir / "sockets"
|
|
89
147
|
locks_dir = cache_dir / "locks"
|
|
90
148
|
sockets_dir.mkdir(parents=True, exist_ok=False)
|
|
@@ -106,43 +164,29 @@ class DataladDataGrabber(BaseDataGrabber):
|
|
|
106
164
|
"Datalad locks set to "
|
|
107
165
|
f"{datalad.cfg.get('datalad.locations.locks')}"
|
|
108
166
|
)
|
|
109
|
-
atexit.register(self.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
super().__init__(datadir=datadir, **kwargs)
|
|
115
|
-
logger.debug("Initializing DataladDataGrabber")
|
|
116
|
-
logger.debug(f"\turi = {uri}")
|
|
117
|
-
logger.debug(f"\t_rootdir = {rootdir}")
|
|
118
|
-
self.uri = uri
|
|
119
|
-
self._rootdir = rootdir
|
|
120
|
-
# Flag to indicate if the dataset was cloned before and it might be
|
|
121
|
-
# dirty
|
|
122
|
-
self.datalad_dirty = False
|
|
167
|
+
atexit.register(_remove_datadir, self.datadir)
|
|
168
|
+
else:
|
|
169
|
+
self._repodir = self.datadir
|
|
170
|
+
super().validate_datagrabber_params()
|
|
123
171
|
|
|
124
172
|
def __del__(self) -> None:
|
|
125
173
|
"""Destructor."""
|
|
126
|
-
if
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
"""Remove temporary directory if it exists."""
|
|
131
|
-
if self._tmpdir.exists():
|
|
132
|
-
logger.debug("Removing temporary directory")
|
|
133
|
-
WorkDirManager().delete_tempdir(self._tmpdir)
|
|
174
|
+
if self.datadir.stem.startswith(
|
|
175
|
+
"datalad"
|
|
176
|
+
) and self.datadir.stem.endswith("juniferauto"):
|
|
177
|
+
_remove_datadir(self.datadir)
|
|
134
178
|
|
|
135
179
|
@property
|
|
136
|
-
def
|
|
137
|
-
"""Get data directory path.
|
|
180
|
+
def fulldir(self) -> Path:
|
|
181
|
+
"""Get complete data directory path.
|
|
138
182
|
|
|
139
183
|
Returns
|
|
140
184
|
-------
|
|
141
185
|
pathlib.Path
|
|
142
|
-
|
|
186
|
+
Complete path to the data directory.
|
|
143
187
|
|
|
144
188
|
"""
|
|
145
|
-
return
|
|
189
|
+
return self._repodir / self.rootdir
|
|
146
190
|
|
|
147
191
|
def _get_dataset_id_remote(self) -> tuple[str, bool]:
|
|
148
192
|
"""Get the dataset ID from the remote.
|
|
@@ -165,8 +209,10 @@ class DataladDataGrabber(BaseDataGrabber):
|
|
|
165
209
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
166
210
|
if not config.get("datagrabber.skipidcheck", False):
|
|
167
211
|
logger.debug(f"Querying {self.uri} for dataset ID")
|
|
168
|
-
repo = GitRepo.clone(
|
|
169
|
-
self.uri,
|
|
212
|
+
repo: GitRepo = GitRepo.clone(
|
|
213
|
+
str(self.uri),
|
|
214
|
+
path=tmpdir,
|
|
215
|
+
clone_options=["-n", "--depth=1"],
|
|
170
216
|
)
|
|
171
217
|
repo.checkout(name=".datalad/config", options=["HEAD"])
|
|
172
218
|
remote_id = repo.config.get("datalad.dataset.id", None)
|
|
@@ -179,10 +225,11 @@ class DataladDataGrabber(BaseDataGrabber):
|
|
|
179
225
|
is_dirty = False
|
|
180
226
|
else:
|
|
181
227
|
logger.debug("Skipping dataset ID check")
|
|
228
|
+
# Should be already set to the dataset
|
|
182
229
|
remote_id = self._dataset.id
|
|
183
230
|
is_dirty = False
|
|
184
231
|
logger.debug(
|
|
185
|
-
f"Remote dataset is {'' if is_dirty else 'not'}
|
|
232
|
+
f"Remote dataset is {'dirty' if is_dirty else 'not dirty'}"
|
|
186
233
|
)
|
|
187
234
|
if remote_id is None:
|
|
188
235
|
raise_error("Could not get dataset ID from remote")
|
|
@@ -252,7 +299,7 @@ class DataladDataGrabber(BaseDataGrabber):
|
|
|
252
299
|
return out
|
|
253
300
|
|
|
254
301
|
def install(self) -> None:
|
|
255
|
-
"""
|
|
302
|
+
"""Installs the datalad dataset.
|
|
256
303
|
|
|
257
304
|
Raises
|
|
258
305
|
------
|
|
@@ -262,12 +309,10 @@ class DataladDataGrabber(BaseDataGrabber):
|
|
|
262
309
|
If there is a datalad-related problem while cloning dataset.
|
|
263
310
|
|
|
264
311
|
"""
|
|
265
|
-
|
|
266
|
-
if
|
|
312
|
+
is_installed = dl.Dataset(self._repodir).is_installed()
|
|
313
|
+
if is_installed:
|
|
267
314
|
logger.debug("Dataset already installed")
|
|
268
|
-
self.
|
|
269
|
-
self._dataset: dl.Dataset = dl.Dataset(self._datadir)
|
|
270
|
-
|
|
315
|
+
self._dataset = dl.Dataset(self._repodir)
|
|
271
316
|
# Check if dataset is already installed with a different ID
|
|
272
317
|
remote_id, is_dirty = self._get_dataset_id_remote()
|
|
273
318
|
if remote_id != self._dataset.id:
|
|
@@ -275,7 +320,6 @@ class DataladDataGrabber(BaseDataGrabber):
|
|
|
275
320
|
"Dataset already installed but with a different "
|
|
276
321
|
f"ID: {self._dataset.id} (local) != {remote_id} (remote)"
|
|
277
322
|
)
|
|
278
|
-
|
|
279
323
|
# Conditional reporting on dataset dirtiness
|
|
280
324
|
self.datalad_dirty = is_dirty
|
|
281
325
|
if self.datalad_dirty:
|
|
@@ -287,18 +331,18 @@ class DataladDataGrabber(BaseDataGrabber):
|
|
|
287
331
|
logger.debug(f"Dataset (id: {self._dataset.id}) is clean")
|
|
288
332
|
|
|
289
333
|
else:
|
|
290
|
-
logger.debug(f"Installing dataset {self.uri} to {self.
|
|
334
|
+
logger.debug(f"Installing dataset {self.uri} to {self._repodir}")
|
|
291
335
|
try:
|
|
292
|
-
self._dataset
|
|
293
|
-
self.uri, self.
|
|
336
|
+
self._dataset = dl.clone(
|
|
337
|
+
self.uri, self._repodir, result_renderer="disabled"
|
|
294
338
|
)
|
|
295
339
|
except IncompleteResultsError as e:
|
|
296
340
|
raise_error(f"Failed to clone dataset: {e.failed}")
|
|
297
341
|
logger.debug("Dataset installed")
|
|
298
|
-
self._was_cloned = not
|
|
299
|
-
|
|
300
|
-
self.datalad_commit_id = self._dataset.repo.get_hexsha(
|
|
301
|
-
self._dataset.repo.get_corresponding_branch()
|
|
342
|
+
self._was_cloned = not is_installed
|
|
343
|
+
# Dataset should be set already
|
|
344
|
+
self.datalad_commit_id = self._dataset.repo.get_hexsha(
|
|
345
|
+
self._dataset.repo.get_corresponding_branch()
|
|
302
346
|
)
|
|
303
347
|
self.datalad_id = self._dataset.id
|
|
304
348
|
|
|
@@ -307,11 +351,18 @@ class DataladDataGrabber(BaseDataGrabber):
|
|
|
307
351
|
if self._was_cloned:
|
|
308
352
|
logger.debug("Removing dataset with reckless='kill'")
|
|
309
353
|
self._dataset.remove(reckless="kill", result_renderer="disabled")
|
|
310
|
-
|
|
354
|
+
elif len(self._got_files) > 0:
|
|
311
355
|
logger.debug("Dropping files that were downloaded")
|
|
312
356
|
for f in self._got_files:
|
|
313
|
-
logger.debug(f"
|
|
314
|
-
|
|
357
|
+
logger.debug(f"\t: {f}")
|
|
358
|
+
# Drop all files in a single call. The files were just obtained
|
|
359
|
+
# from a remote, so skip checking that they are still available
|
|
360
|
+
# there, which would contact the remote for each file.
|
|
361
|
+
self._dataset.drop(
|
|
362
|
+
self._got_files,
|
|
363
|
+
reckless="availability",
|
|
364
|
+
result_renderer="disabled",
|
|
365
|
+
)
|
|
315
366
|
|
|
316
367
|
def __getitem__(self, element: Element) -> dict:
|
|
317
368
|
"""Implement single element indexing in the Datalad database.
|
|
@@ -321,7 +372,7 @@ class DataladDataGrabber(BaseDataGrabber):
|
|
|
321
372
|
|
|
322
373
|
Parameters
|
|
323
374
|
----------
|
|
324
|
-
element :
|
|
375
|
+
element : `Element`
|
|
325
376
|
The element to be indexed. If one string is provided, it is
|
|
326
377
|
assumed to be a tuple with only one item. If a tuple is provided,
|
|
327
378
|
each item in the tuple is the value for the replacement string
|