junifer 0.0.5.dev242__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.dev242.dist-info → junifer-0.0.6.dist-info}/METADATA +43 -38
- junifer-0.0.6.dist-info/RECORD +350 -0
- {junifer-0.0.5.dev242.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.dev242.dist-info/RECORD +0 -275
- junifer-0.0.5.dev242.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.dev242.dist-info → junifer-0.0.6.dist-info/licenses}/AUTHORS.rst +0 -0
- {junifer-0.0.5.dev242.dist-info → junifer-0.0.6.dist-info/licenses}/LICENSE.md +0 -0
- {junifer-0.0.5.dev242.dist-info → junifer-0.0.6.dist-info}/top_level.txt +0 -0
junifer/cli/parser.py
ADDED
@@ -0,0 +1,235 @@
|
|
1
|
+
"""Provide functions for CLI parser."""
|
2
|
+
|
3
|
+
# Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
|
4
|
+
# Synchon Mandal <s.mandal@fz-juelich.de>
|
5
|
+
# License: AGPL
|
6
|
+
|
7
|
+
import importlib
|
8
|
+
import importlib.util
|
9
|
+
import sys
|
10
|
+
from pathlib import Path
|
11
|
+
from typing import Union
|
12
|
+
|
13
|
+
import pandas as pd
|
14
|
+
|
15
|
+
from ..typing import Elements
|
16
|
+
from ..utils import logger, raise_error, warn_with_log, yaml
|
17
|
+
|
18
|
+
|
19
|
+
__all__ = ["parse_elements", "parse_yaml"]
|
20
|
+
|
21
|
+
|
22
|
+
def parse_yaml(filepath: Union[str, Path]) -> dict: # noqa: C901
|
23
|
+
"""Parse YAML.
|
24
|
+
|
25
|
+
Parameters
|
26
|
+
----------
|
27
|
+
filepath : str or pathlib.Path
|
28
|
+
The filepath to read from.
|
29
|
+
|
30
|
+
Returns
|
31
|
+
-------
|
32
|
+
dict
|
33
|
+
The contents represented as dictionary.
|
34
|
+
|
35
|
+
"""
|
36
|
+
# Convert str to Path
|
37
|
+
if not isinstance(filepath, Path):
|
38
|
+
filepath = Path(filepath)
|
39
|
+
|
40
|
+
logger.info(f"Parsing yaml file: {filepath.absolute()!s}")
|
41
|
+
# Filepath existence check
|
42
|
+
if not filepath.exists():
|
43
|
+
raise_error(f"File does not exist: {filepath.absolute()!s}")
|
44
|
+
# Filepath reading
|
45
|
+
contents = yaml.load(filepath)
|
46
|
+
if "elements" in contents:
|
47
|
+
if contents["elements"] is None:
|
48
|
+
raise_error(
|
49
|
+
"The elements key was defined but its content is empty. "
|
50
|
+
"Please define the elements to operate on or remove the key."
|
51
|
+
)
|
52
|
+
# load modules
|
53
|
+
if "with" in contents:
|
54
|
+
to_load = contents["with"]
|
55
|
+
# Convert load modules to list
|
56
|
+
if not isinstance(to_load, list):
|
57
|
+
to_load = [to_load]
|
58
|
+
# Initialize list to have absolute paths for custom modules
|
59
|
+
final_to_load = []
|
60
|
+
for t_module in to_load:
|
61
|
+
if t_module.endswith(".py"):
|
62
|
+
logger.debug(f"Importing file: {t_module}")
|
63
|
+
# This resolves both absolute and relative paths
|
64
|
+
file_path = filepath.parent / t_module
|
65
|
+
if not file_path.exists():
|
66
|
+
raise_error(
|
67
|
+
f"File in 'with' section does not exist: {file_path}"
|
68
|
+
)
|
69
|
+
# Add the parent directory to the sys.path so that the
|
70
|
+
# any imports from this module work correctly
|
71
|
+
t_path = str(file_path.parent)
|
72
|
+
if t_path not in sys.path:
|
73
|
+
sys.path.append(str(file_path.parent))
|
74
|
+
|
75
|
+
spec = importlib.util.spec_from_file_location(
|
76
|
+
t_module, file_path
|
77
|
+
)
|
78
|
+
module = importlib.util.module_from_spec(spec) # type: ignore
|
79
|
+
sys.modules[t_module] = module
|
80
|
+
spec.loader.exec_module(module) # type: ignore
|
81
|
+
|
82
|
+
# Add absolute path to final list
|
83
|
+
final_to_load.append(str(file_path.resolve()))
|
84
|
+
|
85
|
+
# Check if the module has junifer_module_deps function
|
86
|
+
if hasattr(module, "junifer_module_deps"):
|
87
|
+
logger.debug(
|
88
|
+
f"Module {t_module} has junifer_module_deps function"
|
89
|
+
)
|
90
|
+
# Get the dependencies
|
91
|
+
deps = module.junifer_module_deps()
|
92
|
+
# Add the dependencies to the final list
|
93
|
+
for dep in deps:
|
94
|
+
if dep not in final_to_load:
|
95
|
+
final_to_load.append(
|
96
|
+
str((file_path.parent / dep).resolve())
|
97
|
+
)
|
98
|
+
else:
|
99
|
+
logger.info(f"Importing module: {t_module}")
|
100
|
+
importlib.import_module(t_module)
|
101
|
+
# Add module to final list
|
102
|
+
final_to_load.append(t_module)
|
103
|
+
|
104
|
+
# Replace modules to be loaded so that custom modules will take the
|
105
|
+
# absolute path. This was not the case as found in #224. Similar thing
|
106
|
+
# is done with the storage URI below.
|
107
|
+
contents["with"] = final_to_load
|
108
|
+
|
109
|
+
# Compute path for the URI parameter in storage files that are relative
|
110
|
+
# This is a tricky thing that appeared in #127. The problem is that
|
111
|
+
# the path in the URI parameter is relative to YAML file, not to the
|
112
|
+
# current working directory. If we leave it as is in the contents
|
113
|
+
# dict, then it will be used later in the ``build`` function as is,
|
114
|
+
# which will be computed relative to the current working directory.
|
115
|
+
# The solution is to compute the absolute path and replace the
|
116
|
+
# relative path in the contents dict with the absolute path.
|
117
|
+
|
118
|
+
# Check if the storage file is defined
|
119
|
+
if "storage" in contents:
|
120
|
+
if "uri" in contents["storage"]:
|
121
|
+
# Check if the storage file is relative
|
122
|
+
uri_path = Path(contents["storage"]["uri"])
|
123
|
+
if not uri_path.is_absolute():
|
124
|
+
# Compute the absolute path
|
125
|
+
contents["storage"]["uri"] = str(
|
126
|
+
(filepath.parent / uri_path).resolve()
|
127
|
+
)
|
128
|
+
|
129
|
+
# Allow relative path if queue env kind is venv; same motivation as above
|
130
|
+
if "queue" in contents:
|
131
|
+
if "env" in contents["queue"]:
|
132
|
+
if "venv" == contents["queue"]["env"]["kind"]:
|
133
|
+
# Check if the env name is relative
|
134
|
+
venv_path = Path(contents["queue"]["env"]["name"])
|
135
|
+
if not venv_path.is_absolute():
|
136
|
+
# Compute the absolute path
|
137
|
+
contents["queue"]["env"]["name"] = str(
|
138
|
+
(filepath.parent / venv_path).resolve()
|
139
|
+
)
|
140
|
+
|
141
|
+
return contents
|
142
|
+
|
143
|
+
|
144
|
+
def parse_elements(
|
145
|
+
element: tuple[str, ...], config: dict
|
146
|
+
) -> Union[Elements, None]:
|
147
|
+
"""Parse elements from cli.
|
148
|
+
|
149
|
+
Parameters
|
150
|
+
----------
|
151
|
+
element : tuple of str
|
152
|
+
The element(s) to operate on.
|
153
|
+
config : dict
|
154
|
+
The configuration to operate using.
|
155
|
+
|
156
|
+
Returns
|
157
|
+
-------
|
158
|
+
list or None
|
159
|
+
The element(s) as list or None.
|
160
|
+
|
161
|
+
Raises
|
162
|
+
------
|
163
|
+
ValueError
|
164
|
+
If no element is found either in the command-line options or
|
165
|
+
the configuration file.
|
166
|
+
|
167
|
+
Warns
|
168
|
+
-----
|
169
|
+
RuntimeWarning
|
170
|
+
If elements are specified both via the command-line options and
|
171
|
+
the configuration file.
|
172
|
+
|
173
|
+
"""
|
174
|
+
logger.debug(f"Parsing elements: {element}")
|
175
|
+
# Early return None to continue with all elements
|
176
|
+
if not element:
|
177
|
+
return None
|
178
|
+
# Check if the element is a file for single element;
|
179
|
+
# if yes, then parse elements from it
|
180
|
+
if len(element) == 1 and Path(element[0]).resolve().is_file():
|
181
|
+
elements = _parse_elements_file(Path(element[0]).resolve())
|
182
|
+
else:
|
183
|
+
# Process multi-keyed elements
|
184
|
+
elements = [tuple(x.split(",")) if "," in x else x for x in element]
|
185
|
+
logger.debug(f"Parsed elements: {elements}")
|
186
|
+
if elements is not None and "elements" in config:
|
187
|
+
warn_with_log(
|
188
|
+
"One or more elements have been specified in both the command "
|
189
|
+
"line and in the config file. The command line has precedence "
|
190
|
+
"over the configuration file. That is, the elements specified "
|
191
|
+
"in the command line will be used. The elements specified in "
|
192
|
+
"the configuration file will be ignored. To remove this warning, "
|
193
|
+
"please remove the `elements` item from the configuration file."
|
194
|
+
)
|
195
|
+
elif elements is None:
|
196
|
+
# Check in config
|
197
|
+
elements = config.get("elements", None)
|
198
|
+
if elements is None:
|
199
|
+
raise_error(
|
200
|
+
"The `elements` key is set in the configuration, but its value"
|
201
|
+
" is `None`. It is likely that there is an empty `elements` "
|
202
|
+
"section in the yaml configuration file."
|
203
|
+
)
|
204
|
+
return elements
|
205
|
+
|
206
|
+
|
207
|
+
def _parse_elements_file(filepath: Path) -> Elements:
|
208
|
+
"""Parse elements from file.
|
209
|
+
|
210
|
+
Parameters
|
211
|
+
----------
|
212
|
+
filepath : pathlib.Path
|
213
|
+
The path to the element file.
|
214
|
+
|
215
|
+
Returns
|
216
|
+
-------
|
217
|
+
list
|
218
|
+
The element(s) as list.
|
219
|
+
|
220
|
+
"""
|
221
|
+
# Read CSV into dataframe
|
222
|
+
csv_df = pd.read_csv(
|
223
|
+
filepath,
|
224
|
+
header=None, # no header # type: ignore
|
225
|
+
index_col=False, # no index column
|
226
|
+
dtype=str,
|
227
|
+
skipinitialspace=True, # no leading space after delimiter
|
228
|
+
)
|
229
|
+
# Remove trailing whitespace in cell entries
|
230
|
+
csv_df_trimmed = csv_df.apply(lambda x: x.str.strip())
|
231
|
+
# Convert to list of tuple of str if more than one column else flatten
|
232
|
+
if len(csv_df_trimmed.columns) == 1:
|
233
|
+
return csv_df_trimmed.to_numpy().flatten().tolist()
|
234
|
+
else:
|
235
|
+
return list(map(tuple, csv_df_trimmed.to_numpy()))
|
junifer/cli/py.typed
ADDED
File without changes
|
@@ -1,18 +1,17 @@
|
|
1
|
-
"""Provide tests for
|
1
|
+
"""Provide tests for CLI."""
|
2
2
|
|
3
3
|
# Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
|
4
4
|
# Synchon Mandal <s.mandal@fz-juelich.de>
|
5
5
|
# License: AGPL
|
6
6
|
|
7
7
|
from pathlib import Path
|
8
|
-
from typing import Callable
|
8
|
+
from typing import Callable
|
9
9
|
|
10
10
|
import pytest
|
11
11
|
from click.testing import CliRunner
|
12
12
|
from ruamel.yaml import YAML
|
13
13
|
|
14
|
-
from junifer.
|
15
|
-
_parse_elements_file,
|
14
|
+
from junifer.cli.cli import (
|
16
15
|
collect,
|
17
16
|
list_elements,
|
18
17
|
queue,
|
@@ -21,6 +20,7 @@ from junifer.api.cli import (
|
|
21
20
|
selftest,
|
22
21
|
wtf,
|
23
22
|
)
|
23
|
+
from junifer.cli.parser import _parse_elements_file
|
24
24
|
|
25
25
|
|
26
26
|
# Configure YAML class
|
@@ -42,7 +42,7 @@ runner = CliRunner()
|
|
42
42
|
],
|
43
43
|
)
|
44
44
|
def test_run_and_collect_commands(
|
45
|
-
tmp_path: Path, elements:
|
45
|
+
tmp_path: Path, elements: tuple[str, ...]
|
46
46
|
) -> None:
|
47
47
|
"""Test run and collect commands.
|
48
48
|
|
@@ -175,7 +175,7 @@ def test_run_using_element_file(tmp_path: Path, elements: str) -> None:
|
|
175
175
|
],
|
176
176
|
)
|
177
177
|
def test_multi_element_access(
|
178
|
-
tmp_path: Path, elements: str, expected_list:
|
178
|
+
tmp_path: Path, elements: str, expected_list: list[tuple[str, ...]]
|
179
179
|
) -> None:
|
180
180
|
"""Test mulit-element parsing.
|
181
181
|
|
@@ -306,7 +306,7 @@ def test_reset(
|
|
306
306
|
],
|
307
307
|
)
|
308
308
|
def test_list_elements_stdout(
|
309
|
-
elements:
|
309
|
+
elements: tuple[str, ...],
|
310
310
|
) -> None:
|
311
311
|
"""Test elements listing to stdout.
|
312
312
|
|
@@ -344,7 +344,7 @@ def test_list_elements_stdout(
|
|
344
344
|
)
|
345
345
|
def test_list_elements_output_file(
|
346
346
|
tmp_path: Path,
|
347
|
-
elements:
|
347
|
+
elements: tuple[str, ...],
|
348
348
|
) -> None:
|
349
349
|
"""Test elements listing to output file.
|
350
350
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
"""Provide tests for utils."""
|
1
|
+
"""Provide tests for CLI utils."""
|
2
2
|
|
3
3
|
# Authors: Synchon Mandal <s.mandal@fz-juelich.de>
|
4
4
|
# License: AGPL
|
@@ -9,7 +9,7 @@ import sys
|
|
9
9
|
import pytest
|
10
10
|
|
11
11
|
from junifer._version import __version__
|
12
|
-
from junifer.
|
12
|
+
from junifer.cli.utils import (
|
13
13
|
_get_dependency_information,
|
14
14
|
_get_environment_information,
|
15
15
|
_get_junifer_version,
|
@@ -43,11 +43,12 @@ def test_get_dependency_information_short() -> None:
|
|
43
43
|
"nilearn",
|
44
44
|
"sqlalchemy",
|
45
45
|
"ruamel.yaml",
|
46
|
-
"httpx",
|
47
46
|
"tqdm",
|
48
47
|
"templateflow",
|
49
48
|
"lapy",
|
49
|
+
"lazy_loader",
|
50
50
|
"looseversion",
|
51
|
+
"junifer_data",
|
51
52
|
]
|
52
53
|
|
53
54
|
if sys.version_info < (3, 11):
|
@@ -72,10 +73,10 @@ def test_get_dependency_information_long() -> None:
|
|
72
73
|
"nilearn",
|
73
74
|
"sqlalchemy",
|
74
75
|
"ruamel.yaml",
|
75
|
-
"httpx",
|
76
76
|
"tqdm",
|
77
77
|
"templateflow",
|
78
78
|
"lapy",
|
79
|
+
"lazy_loader",
|
79
80
|
]
|
80
81
|
for key in dependency_list:
|
81
82
|
assert key in dependency_information_keys
|
@@ -1,4 +1,4 @@
|
|
1
|
-
"""Provide tests for parser."""
|
1
|
+
"""Provide tests for CLI parser."""
|
2
2
|
|
3
3
|
# Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
|
4
4
|
# Synchon Mandal <s.mandal@fz-juelich.de>
|
@@ -9,7 +9,7 @@ from pathlib import Path
|
|
9
9
|
|
10
10
|
import pytest
|
11
11
|
|
12
|
-
from junifer.
|
12
|
+
from junifer.cli.parser import parse_yaml
|
13
13
|
|
14
14
|
|
15
15
|
def test_parse_yaml_failure() -> None:
|
junifer/{api → cli}/utils.py
RENAMED
@@ -1,4 +1,4 @@
|
|
1
|
-
"""Provide utility functions for the
|
1
|
+
"""Provide utility functions for the cli sub-package."""
|
2
2
|
|
3
3
|
# Authors: Synchon Mandal <s.mandal@fz-juelich.de>
|
4
4
|
# License: AGPL
|
@@ -7,22 +7,12 @@ import os
|
|
7
7
|
import platform as pl
|
8
8
|
import re
|
9
9
|
from importlib.metadata import distribution
|
10
|
-
from typing import Dict
|
11
|
-
|
12
|
-
from ruamel.yaml import YAML
|
13
10
|
|
14
11
|
from .._version import __version__
|
15
12
|
from ..utils.logging import get_versions
|
16
13
|
|
17
14
|
|
18
|
-
|
19
|
-
yaml = YAML()
|
20
|
-
yaml.default_flow_style = False
|
21
|
-
yaml.allow_unicode = True
|
22
|
-
yaml.indent(mapping=2, sequence=4, offset=2)
|
23
|
-
|
24
|
-
|
25
|
-
def _get_junifer_version() -> Dict[str, str]:
|
15
|
+
def _get_junifer_version() -> dict[str, str]:
|
26
16
|
"""Get junifer version information.
|
27
17
|
|
28
18
|
Returns
|
@@ -36,7 +26,7 @@ def _get_junifer_version() -> Dict[str, str]:
|
|
36
26
|
}
|
37
27
|
|
38
28
|
|
39
|
-
def _get_python_information() ->
|
29
|
+
def _get_python_information() -> dict[str, str]:
|
40
30
|
"""Get installed Python information.
|
41
31
|
|
42
32
|
Parameters
|
@@ -51,7 +41,7 @@ def _get_python_information() -> Dict[str, str]:
|
|
51
41
|
}
|
52
42
|
|
53
43
|
|
54
|
-
def _get_dependency_information(long_: bool) ->
|
44
|
+
def _get_dependency_information(long_: bool) -> dict[str, str]:
|
55
45
|
"""Get Python environment dependency information.
|
56
46
|
|
57
47
|
Parameters
|
@@ -96,7 +86,7 @@ def _get_dependency_information(long_: bool) -> Dict[str, str]:
|
|
96
86
|
return pruned_dependency_versions
|
97
87
|
|
98
88
|
|
99
|
-
def _get_system_information() ->
|
89
|
+
def _get_system_information() -> dict[str, str]:
|
100
90
|
"""Get system information.
|
101
91
|
|
102
92
|
Returns
|
@@ -110,7 +100,7 @@ def _get_system_information() -> Dict[str, str]:
|
|
110
100
|
}
|
111
101
|
|
112
102
|
|
113
|
-
def _get_environment_information(long_: bool) ->
|
103
|
+
def _get_environment_information(long_: bool) -> dict[str, str]:
|
114
104
|
"""Get system environment information.
|
115
105
|
|
116
106
|
Parameters
|
@@ -5,17 +5,7 @@
|
|
5
5
|
# Synchon Mandal <s.mandal@fz-juelich.de>
|
6
6
|
# License: AGPL
|
7
7
|
|
8
|
-
|
9
|
-
from .camcan_vbm import JuselessDataladCamCANVBM
|
10
|
-
from .ixi_vbm import JuselessDataladIXIVBM
|
11
|
-
from .ucla import JuselessUCLA
|
12
|
-
from .ukb_vbm import JuselessDataladUKBVBM
|
8
|
+
import lazy_loader as lazy
|
13
9
|
|
14
10
|
|
15
|
-
__all__ =
|
16
|
-
"JuselessDataladAOMICID1000VBM",
|
17
|
-
"JuselessDataladCamCANVBM",
|
18
|
-
"JuselessDataladIXIVBM",
|
19
|
-
"JuselessUCLA",
|
20
|
-
"JuselessDataladUKBVBM",
|
21
|
-
]
|
11
|
+
__getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__)
|
@@ -0,0 +1,13 @@
|
|
1
|
+
__all__ = [
|
2
|
+
"JuselessDataladAOMICID1000VBM",
|
3
|
+
"JuselessDataladCamCANVBM",
|
4
|
+
"JuselessDataladIXIVBM",
|
5
|
+
"JuselessUCLA",
|
6
|
+
"JuselessDataladUKBVBM",
|
7
|
+
]
|
8
|
+
|
9
|
+
from .aomic_id1000_vbm import JuselessDataladAOMICID1000VBM
|
10
|
+
from .camcan_vbm import JuselessDataladCamCANVBM
|
11
|
+
from .ixi_vbm import JuselessDataladIXIVBM
|
12
|
+
from .ucla import JuselessUCLA
|
13
|
+
from .ukb_vbm import JuselessDataladUKBVBM
|
@@ -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 ....api.decorators import register_datagrabber
|
12
12
|
from ....datagrabber import PatternDataladDataGrabber
|
@@ -37,7 +37,7 @@ class JuselessDataladIXIVBM(PatternDataladDataGrabber):
|
|
37
37
|
def __init__(
|
38
38
|
self,
|
39
39
|
datadir: Union[str, Path, None] = None,
|
40
|
-
sites: Union[str,
|
40
|
+
sites: Union[str, list[str], None] = None,
|
41
41
|
) -> None:
|
42
42
|
uri = (
|
43
43
|
"ria+http://cat_12.5.ds.inm7.de"
|
File without changes
|
@@ -6,7 +6,7 @@
|
|
6
6
|
# License: AGPL
|
7
7
|
|
8
8
|
import socket
|
9
|
-
from typing import
|
9
|
+
from typing import Optional, Union
|
10
10
|
|
11
11
|
import pytest
|
12
12
|
|
@@ -53,7 +53,7 @@ def test_JuselessUCLA() -> None:
|
|
53
53
|
],
|
54
54
|
)
|
55
55
|
def test_JuselessUCLA_partial_data_access(
|
56
|
-
types: Union[str,
|
56
|
+
types: Union[str, list[str]],
|
57
57
|
) -> None:
|
58
58
|
"""Test JuselessUCLA DataGrabber partial data access.
|
59
59
|
|
@@ -5,7 +5,7 @@
|
|
5
5
|
# License: AGPL
|
6
6
|
|
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 ....datagrabber import PatternDataGrabber
|
@@ -43,8 +43,8 @@ class JuselessUCLA(PatternDataGrabber):
|
|
43
43
|
datadir: Union[
|
44
44
|
str, Path
|
45
45
|
] = "/data/project/psychosis_thalamus/data/fmriprep",
|
46
|
-
types: Union[str,
|
47
|
-
tasks: Union[str,
|
46
|
+
types: Union[str, list[str], None] = None,
|
47
|
+
tasks: Union[str, list[str], None] = None,
|
48
48
|
) -> None:
|
49
49
|
# Declare all tasks
|
50
50
|
all_tasks = [
|
@@ -136,7 +136,7 @@ class JuselessUCLA(PatternDataGrabber):
|
|
136
136
|
confounds_format="fmriprep",
|
137
137
|
)
|
138
138
|
|
139
|
-
def get_elements(self) ->
|
139
|
+
def get_elements(self) -> list:
|
140
140
|
"""Implement fetching list of elements in the dataset.
|
141
141
|
|
142
142
|
Returns
|
File without changes
|
junifer/conftest.py
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
"""Provide conftest for pytest."""
|
2
|
+
|
3
|
+
# Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
|
4
|
+
# License: AGPL
|
5
|
+
|
6
|
+
import pytest
|
7
|
+
|
8
|
+
from junifer.utils.singleton import Singleton
|
9
|
+
|
10
|
+
|
11
|
+
@pytest.fixture(autouse=True)
|
12
|
+
def reset_singletons() -> None:
|
13
|
+
"""Reset all singletons."""
|
14
|
+
to_clean = ["WorkDirManager"]
|
15
|
+
to_remove = [
|
16
|
+
v for k, v in Singleton.instances.items() if k.__name__ in to_clean
|
17
|
+
]
|
18
|
+
Singleton.instances = {
|
19
|
+
k: v
|
20
|
+
for k, v in Singleton.instances.items()
|
21
|
+
if k.__name__ not in to_clean
|
22
|
+
}
|
23
|
+
# Force deleting the singletons
|
24
|
+
for elem in to_remove:
|
25
|
+
del elem
|
junifer/data/__init__.py
CHANGED
@@ -4,47 +4,7 @@
|
|
4
4
|
# Synchon Mandal <s.mandal@fz-juelich.de>
|
5
5
|
# License: AGPL
|
6
6
|
|
7
|
-
|
8
|
-
list_coordinates,
|
9
|
-
load_coordinates,
|
10
|
-
register_coordinates,
|
11
|
-
get_coordinates,
|
12
|
-
)
|
13
|
-
from .parcellations import (
|
14
|
-
list_parcellations,
|
15
|
-
load_parcellation,
|
16
|
-
register_parcellation,
|
17
|
-
merge_parcellations,
|
18
|
-
get_parcellation,
|
19
|
-
)
|
7
|
+
import lazy_loader as lazy
|
20
8
|
|
21
|
-
from .masks import (
|
22
|
-
list_masks,
|
23
|
-
load_mask,
|
24
|
-
register_mask,
|
25
|
-
get_mask,
|
26
|
-
)
|
27
9
|
|
28
|
-
|
29
|
-
|
30
|
-
from . import utils
|
31
|
-
|
32
|
-
|
33
|
-
__all__ = [
|
34
|
-
"list_coordinates",
|
35
|
-
"load_coordinates",
|
36
|
-
"register_coordinates",
|
37
|
-
"get_coordinates",
|
38
|
-
"list_parcellations",
|
39
|
-
"load_parcellation",
|
40
|
-
"register_parcellation",
|
41
|
-
"merge_parcellations",
|
42
|
-
"get_parcellation",
|
43
|
-
"list_masks",
|
44
|
-
"load_mask",
|
45
|
-
"register_mask",
|
46
|
-
"get_mask",
|
47
|
-
"get_template",
|
48
|
-
"get_xfm",
|
49
|
-
"utils",
|
50
|
-
]
|
10
|
+
__getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__)
|
@@ -0,0 +1,29 @@
|
|
1
|
+
__all__ = [
|
2
|
+
"CoordinatesRegistry",
|
3
|
+
"ParcellationRegistry",
|
4
|
+
"MaskRegistry",
|
5
|
+
"get_data",
|
6
|
+
"list_data",
|
7
|
+
"load_data",
|
8
|
+
"register_data",
|
9
|
+
"deregister_data",
|
10
|
+
"get_template",
|
11
|
+
"get_xfm",
|
12
|
+
"utils",
|
13
|
+
]
|
14
|
+
|
15
|
+
from .coordinates import CoordinatesRegistry
|
16
|
+
from .parcellations import ParcellationRegistry
|
17
|
+
from .masks import MaskRegistry
|
18
|
+
|
19
|
+
from ._dispatch import (
|
20
|
+
get_data,
|
21
|
+
list_data,
|
22
|
+
load_data,
|
23
|
+
register_data,
|
24
|
+
deregister_data,
|
25
|
+
)
|
26
|
+
|
27
|
+
from .template_spaces import get_template, get_xfm
|
28
|
+
|
29
|
+
from . import utils
|