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
@@ -0,0 +1,200 @@
|
|
1
|
+
"""Provide tests for PipelineComponentRegistry."""
|
2
|
+
|
3
|
+
# Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
|
4
|
+
# Leonard Sasse <l.sasse@fz-juelich.de>
|
5
|
+
# Synchon Mandal <s.mandal@fz-juelich.de>
|
6
|
+
# License: AGPL
|
7
|
+
|
8
|
+
import logging
|
9
|
+
from abc import ABC
|
10
|
+
|
11
|
+
import pytest
|
12
|
+
|
13
|
+
from junifer.datagrabber.pattern import PatternDataGrabber
|
14
|
+
from junifer.pipeline.pipeline_component_registry import (
|
15
|
+
PipelineComponentRegistry,
|
16
|
+
)
|
17
|
+
from junifer.storage import SQLiteFeatureStorage
|
18
|
+
|
19
|
+
|
20
|
+
def test_pipeline_component_registry_singleton() -> None:
|
21
|
+
"""Test that PipelineComponentRegistry is a singleton."""
|
22
|
+
registry_1 = PipelineComponentRegistry()
|
23
|
+
registry_2 = PipelineComponentRegistry()
|
24
|
+
assert id(registry_1) == id(registry_2)
|
25
|
+
|
26
|
+
|
27
|
+
def test_pipeline_component_registry_register_invalid_step():
|
28
|
+
"""Test invalid step name during component registration."""
|
29
|
+
with pytest.raises(ValueError, match="Invalid step:"):
|
30
|
+
PipelineComponentRegistry().register(step="foo", klass=str)
|
31
|
+
|
32
|
+
|
33
|
+
def test_pipeline_component_registry_steps():
|
34
|
+
"""Test steps for PipelineComponentRegistry."""
|
35
|
+
assert set(PipelineComponentRegistry().steps) == {
|
36
|
+
"datagrabber",
|
37
|
+
"datareader",
|
38
|
+
"preprocessing",
|
39
|
+
"marker",
|
40
|
+
"storage",
|
41
|
+
}
|
42
|
+
|
43
|
+
|
44
|
+
def test_pipeline_component_registry_components():
|
45
|
+
"""Test components for PipelineComponentRegistry."""
|
46
|
+
assert set(PipelineComponentRegistry().steps) == {
|
47
|
+
"datagrabber",
|
48
|
+
"datareader",
|
49
|
+
"preprocessing",
|
50
|
+
"marker",
|
51
|
+
"storage",
|
52
|
+
}
|
53
|
+
|
54
|
+
|
55
|
+
@pytest.mark.parametrize(
|
56
|
+
"step, klass",
|
57
|
+
[
|
58
|
+
("datagrabber", PatternDataGrabber),
|
59
|
+
("storage", SQLiteFeatureStorage),
|
60
|
+
],
|
61
|
+
)
|
62
|
+
def test_pipeline_component_registry_register(
|
63
|
+
caplog: pytest.LogCaptureFixture, step: str, klass: type
|
64
|
+
) -> None:
|
65
|
+
"""Test register for PipelineComponentRegistry.
|
66
|
+
|
67
|
+
Parameters
|
68
|
+
----------
|
69
|
+
caplog : pytest.LogCaptureFixture
|
70
|
+
The pytest.LogCaptureFixture object.
|
71
|
+
step : str
|
72
|
+
The parametrized name of the step.
|
73
|
+
klass : str
|
74
|
+
The parametrized name of the class.
|
75
|
+
|
76
|
+
"""
|
77
|
+
with caplog.at_level(logging.INFO):
|
78
|
+
# Register
|
79
|
+
PipelineComponentRegistry().register(step=step, klass=klass)
|
80
|
+
# Check logging message
|
81
|
+
assert "Registering" in caplog.text
|
82
|
+
|
83
|
+
|
84
|
+
@pytest.mark.parametrize(
|
85
|
+
"step, klass",
|
86
|
+
[
|
87
|
+
("datagrabber", PatternDataGrabber),
|
88
|
+
("storage", SQLiteFeatureStorage),
|
89
|
+
],
|
90
|
+
)
|
91
|
+
def test_pipeline_component_registry_deregister(
|
92
|
+
caplog: pytest.LogCaptureFixture, step: str, klass: type
|
93
|
+
) -> None:
|
94
|
+
"""Test de-register for PipelineComponentRegistry.
|
95
|
+
|
96
|
+
Parameters
|
97
|
+
----------
|
98
|
+
caplog : pytest.LogCaptureFixture
|
99
|
+
The pytest.LogCaptureFixture object.
|
100
|
+
step : str
|
101
|
+
The parametrized name of the step.
|
102
|
+
klass : str
|
103
|
+
The parametrized name of the class.
|
104
|
+
|
105
|
+
"""
|
106
|
+
with caplog.at_level(logging.INFO):
|
107
|
+
# Register
|
108
|
+
PipelineComponentRegistry().deregister(step=step, klass=klass)
|
109
|
+
# Check logging message
|
110
|
+
assert "De-registering" in caplog.text
|
111
|
+
|
112
|
+
|
113
|
+
def test_pipeline_component_registry_step_components() -> None:
|
114
|
+
"""Test step components for PipelineComponentRegistry."""
|
115
|
+
# Check absent name
|
116
|
+
assert "fizz" not in PipelineComponentRegistry().step_components(
|
117
|
+
step="datagrabber"
|
118
|
+
)
|
119
|
+
|
120
|
+
# Create new class
|
121
|
+
class fizz(str):
|
122
|
+
pass
|
123
|
+
|
124
|
+
# Register datagrabber
|
125
|
+
PipelineComponentRegistry().register(step="datagrabber", klass=fizz)
|
126
|
+
# Check registered component
|
127
|
+
assert "fizz" in PipelineComponentRegistry().step_components(
|
128
|
+
step="datagrabber"
|
129
|
+
)
|
130
|
+
|
131
|
+
|
132
|
+
def test_pipeline_component_registry_get_class_invalid_name() -> None:
|
133
|
+
"""Test get class invalid name for PipelineComponentRegistry."""
|
134
|
+
with pytest.raises(ValueError, match="Invalid name:"):
|
135
|
+
PipelineComponentRegistry().get_class(step="datagrabber", name="foo")
|
136
|
+
|
137
|
+
|
138
|
+
def test_pipeline_component_registry_get_class():
|
139
|
+
"""Test get class for PipelineComponentRegistry."""
|
140
|
+
|
141
|
+
# Create new class
|
142
|
+
class bar(str):
|
143
|
+
pass
|
144
|
+
|
145
|
+
# Register datagrabber
|
146
|
+
PipelineComponentRegistry().register(step="datagrabber", klass=bar)
|
147
|
+
# Get class
|
148
|
+
obj = PipelineComponentRegistry().get_class(step="datagrabber", name="bar")
|
149
|
+
assert isinstance(obj, type(bar))
|
150
|
+
|
151
|
+
|
152
|
+
def test_pipeline_component_registry_build():
|
153
|
+
"""Test component instance building for PipelineComponentRegistry."""
|
154
|
+
import numpy as np
|
155
|
+
|
156
|
+
# Define abstract base class
|
157
|
+
class SuperClass(ABC):
|
158
|
+
pass
|
159
|
+
|
160
|
+
# Define concrete class
|
161
|
+
class ConcreteClass(SuperClass):
|
162
|
+
def __init__(self, value=1):
|
163
|
+
self.value = value
|
164
|
+
|
165
|
+
# Register
|
166
|
+
PipelineComponentRegistry().register(
|
167
|
+
step="datagrabber", klass=ConcreteClass
|
168
|
+
)
|
169
|
+
|
170
|
+
# Build
|
171
|
+
obj = PipelineComponentRegistry().build_component_instance(
|
172
|
+
step="datagrabber", name="ConcreteClass", baseclass=SuperClass
|
173
|
+
)
|
174
|
+
assert isinstance(obj, ConcreteClass)
|
175
|
+
assert obj.value == 1
|
176
|
+
|
177
|
+
# Build
|
178
|
+
obj = PipelineComponentRegistry().build_component_instance(
|
179
|
+
step="datagrabber",
|
180
|
+
name="ConcreteClass",
|
181
|
+
baseclass=SuperClass,
|
182
|
+
init_params={"value": 2},
|
183
|
+
)
|
184
|
+
assert isinstance(obj, ConcreteClass)
|
185
|
+
assert obj.value == 2
|
186
|
+
|
187
|
+
# Check error
|
188
|
+
with pytest.raises(ValueError, match="Must inherit"):
|
189
|
+
PipelineComponentRegistry().build_component_instance(
|
190
|
+
step="datagrabber", name="ConcreteClass", baseclass=np.ndarray
|
191
|
+
)
|
192
|
+
|
193
|
+
# Check error
|
194
|
+
with pytest.raises(RuntimeError, match="Failed to create"):
|
195
|
+
PipelineComponentRegistry().build_component_instance(
|
196
|
+
step="datagrabber",
|
197
|
+
name="ConcreteClass",
|
198
|
+
baseclass=SuperClass,
|
199
|
+
init_params={"wrong": 2},
|
200
|
+
)
|
@@ -5,12 +5,17 @@
|
|
5
5
|
# License: AGPL
|
6
6
|
|
7
7
|
import warnings
|
8
|
-
from typing import ClassVar
|
8
|
+
from typing import ClassVar
|
9
9
|
|
10
10
|
import pytest
|
11
11
|
|
12
12
|
from junifer.pipeline.pipeline_step_mixin import PipelineStepMixin
|
13
13
|
from junifer.pipeline.utils import _check_afni
|
14
|
+
from junifer.typing import (
|
15
|
+
ConditionalDependencies,
|
16
|
+
Dependencies,
|
17
|
+
ExternalDependencies,
|
18
|
+
)
|
14
19
|
|
15
20
|
|
16
21
|
def test_PipelineStepMixin_correct_dependencies() -> None:
|
@@ -19,15 +24,15 @@ def test_PipelineStepMixin_correct_dependencies() -> None:
|
|
19
24
|
class CorrectMixer(PipelineStepMixin):
|
20
25
|
"""Test class for validation."""
|
21
26
|
|
22
|
-
_DEPENDENCIES: ClassVar[
|
27
|
+
_DEPENDENCIES: ClassVar[Dependencies] = {"math"}
|
23
28
|
|
24
|
-
def validate_input(self, input:
|
29
|
+
def validate_input(self, input: list[str]) -> list[str]:
|
25
30
|
return input
|
26
31
|
|
27
32
|
def get_output_type(self, input_type: str) -> str:
|
28
33
|
return input_type
|
29
34
|
|
30
|
-
def _fit_transform(self, input:
|
35
|
+
def _fit_transform(self, input: dict[str, dict]) -> dict[str, dict]:
|
31
36
|
return {"input": input}
|
32
37
|
|
33
38
|
mixer = CorrectMixer()
|
@@ -40,15 +45,15 @@ def test_PipelineStepMixin_incorrect_dependencies() -> None:
|
|
40
45
|
class IncorrectMixer(PipelineStepMixin):
|
41
46
|
"""Test class for validation."""
|
42
47
|
|
43
|
-
_DEPENDENCIES: ClassVar[
|
48
|
+
_DEPENDENCIES: ClassVar[Dependencies] = {"foobar"}
|
44
49
|
|
45
|
-
def validate_input(self, input:
|
50
|
+
def validate_input(self, input: list[str]) -> list[str]:
|
46
51
|
return input
|
47
52
|
|
48
53
|
def get_output_type(self, input_type: str) -> str:
|
49
54
|
return input_type
|
50
55
|
|
51
|
-
def _fit_transform(self, input:
|
56
|
+
def _fit_transform(self, input: dict[str, dict]) -> dict[str, dict]:
|
52
57
|
return {"input": input}
|
53
58
|
|
54
59
|
mixer = IncorrectMixer()
|
@@ -65,15 +70,15 @@ def test_PipelineStepMixin_correct_ext_dependencies() -> None:
|
|
65
70
|
class CorrectMixer(PipelineStepMixin):
|
66
71
|
"""Test class for validation."""
|
67
72
|
|
68
|
-
_EXT_DEPENDENCIES: ClassVar[
|
73
|
+
_EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [{"name": "afni"}]
|
69
74
|
|
70
|
-
def validate_input(self, input:
|
75
|
+
def validate_input(self, input: list[str]) -> list[str]:
|
71
76
|
return input
|
72
77
|
|
73
78
|
def get_output_type(self, input_type: str) -> str:
|
74
79
|
return input_type
|
75
80
|
|
76
|
-
def _fit_transform(self, input:
|
81
|
+
def _fit_transform(self, input: dict[str, dict]) -> dict[str, dict]:
|
77
82
|
return {"input": input}
|
78
83
|
|
79
84
|
mixer = CorrectMixer()
|
@@ -89,17 +94,17 @@ def test_PipelineStepMixin_ext_deps_correct_commands() -> None:
|
|
89
94
|
class CorrectMixer(PipelineStepMixin):
|
90
95
|
"""Test class for validation."""
|
91
96
|
|
92
|
-
_EXT_DEPENDENCIES: ClassVar[
|
97
|
+
_EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [
|
93
98
|
{"name": "afni", "commands": ["3dReHo"]}
|
94
99
|
]
|
95
100
|
|
96
|
-
def validate_input(self, input:
|
101
|
+
def validate_input(self, input: list[str]) -> list[str]:
|
97
102
|
return input
|
98
103
|
|
99
104
|
def get_output_type(self, input_type: str) -> str:
|
100
105
|
return input_type
|
101
106
|
|
102
|
-
def _fit_transform(self, input:
|
107
|
+
def _fit_transform(self, input: dict[str, dict]) -> dict[str, dict]:
|
103
108
|
return {"input": input}
|
104
109
|
|
105
110
|
mixer = CorrectMixer()
|
@@ -117,17 +122,17 @@ def test_PipelineStepMixin_ext_deps_incorrect_commands() -> None:
|
|
117
122
|
class CorrectMixer(PipelineStepMixin):
|
118
123
|
"""Test class for validation."""
|
119
124
|
|
120
|
-
_EXT_DEPENDENCIES: ClassVar[
|
125
|
+
_EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [
|
121
126
|
{"name": "afni", "commands": ["3d"]}
|
122
127
|
]
|
123
128
|
|
124
|
-
def validate_input(self, input:
|
129
|
+
def validate_input(self, input: list[str]) -> list[str]:
|
125
130
|
return input
|
126
131
|
|
127
132
|
def get_output_type(self, input_type: str) -> str:
|
128
133
|
return input_type
|
129
134
|
|
130
|
-
def _fit_transform(self, input:
|
135
|
+
def _fit_transform(self, input: dict[str, dict]) -> dict[str, dict]:
|
131
136
|
return {"input": input}
|
132
137
|
|
133
138
|
mixer = CorrectMixer()
|
@@ -141,17 +146,17 @@ def test_PipelineStepMixin_incorrect_ext_dependencies() -> None:
|
|
141
146
|
class IncorrectMixer(PipelineStepMixin):
|
142
147
|
"""Test class for validation."""
|
143
148
|
|
144
|
-
_EXT_DEPENDENCIES: ClassVar[
|
149
|
+
_EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [
|
145
150
|
{"name": "foobar", "optional": True}
|
146
151
|
]
|
147
152
|
|
148
|
-
def validate_input(self, input:
|
153
|
+
def validate_input(self, input: list[str]) -> list[str]:
|
149
154
|
return input
|
150
155
|
|
151
156
|
def get_output_type(self, input_type: str) -> str:
|
152
157
|
return input_type
|
153
158
|
|
154
|
-
def _fit_transform(self, input:
|
159
|
+
def _fit_transform(self, input: dict[str, dict]) -> dict[str, dict]:
|
155
160
|
return {"input": input}
|
156
161
|
|
157
162
|
mixer = IncorrectMixer()
|
@@ -163,14 +168,12 @@ def test_PipelineStepMixin_correct_conditional_dependencies() -> None:
|
|
163
168
|
"""Test fit-transform with correct conditional dependencies."""
|
164
169
|
|
165
170
|
class Dependency:
|
166
|
-
_DEPENDENCIES: ClassVar[
|
171
|
+
_DEPENDENCIES: ClassVar[Dependencies] = {"math"}
|
167
172
|
|
168
173
|
class CorrectMixer(PipelineStepMixin):
|
169
174
|
"""Test class for validation."""
|
170
175
|
|
171
|
-
_CONDITIONAL_DEPENDENCIES: ClassVar[
|
172
|
-
List[Dict[str, Union[str, Type]]]
|
173
|
-
] = [
|
176
|
+
_CONDITIONAL_DEPENDENCIES: ClassVar[ConditionalDependencies] = [
|
174
177
|
{
|
175
178
|
"using": "math",
|
176
179
|
"depends_on": Dependency,
|
@@ -179,13 +182,13 @@ def test_PipelineStepMixin_correct_conditional_dependencies() -> None:
|
|
179
182
|
|
180
183
|
using = "math"
|
181
184
|
|
182
|
-
def validate_input(self, input:
|
185
|
+
def validate_input(self, input: list[str]) -> list[str]:
|
183
186
|
return input
|
184
187
|
|
185
188
|
def get_output_type(self, input_type: str) -> str:
|
186
189
|
return input_type
|
187
190
|
|
188
|
-
def _fit_transform(self, input:
|
191
|
+
def _fit_transform(self, input: dict[str, dict]) -> dict[str, dict]:
|
189
192
|
return {"input": input}
|
190
193
|
|
191
194
|
mixer = CorrectMixer()
|
@@ -196,27 +199,25 @@ def test_PipelineStepMixin_incorrect_conditional_dependencies() -> None:
|
|
196
199
|
"""Test fit-transform with incorrect conditional dependencies."""
|
197
200
|
|
198
201
|
class Dependency:
|
199
|
-
_DEPENDENCIES: ClassVar[
|
202
|
+
_DEPENDENCIES: ClassVar[Dependencies] = {"math"}
|
200
203
|
|
201
204
|
class IncorrectMixer(PipelineStepMixin):
|
202
205
|
"""Test class for validation."""
|
203
206
|
|
204
|
-
_CONDITIONAL_DEPENDENCIES: ClassVar[
|
205
|
-
List[Dict[str, Union[str, Type]]]
|
206
|
-
] = [
|
207
|
+
_CONDITIONAL_DEPENDENCIES: ClassVar[ConditionalDependencies] = [
|
207
208
|
{
|
208
209
|
"using": "math",
|
209
210
|
"depends_on": Dependency,
|
210
211
|
},
|
211
212
|
]
|
212
213
|
|
213
|
-
def validate_input(self, input:
|
214
|
+
def validate_input(self, input: list[str]) -> list[str]:
|
214
215
|
return input
|
215
216
|
|
216
217
|
def get_output_type(self, input_type: str) -> str:
|
217
218
|
return input_type
|
218
219
|
|
219
|
-
def _fit_transform(self, input:
|
220
|
+
def _fit_transform(self, input: dict[str, dict]) -> dict[str, dict]:
|
220
221
|
return {"input": input}
|
221
222
|
|
222
223
|
mixer = IncorrectMixer()
|
@@ -231,14 +232,12 @@ def test_PipelineStepMixin_correct_conditional_ext_dependencies() -> None:
|
|
231
232
|
"""Test fit-transform with correct conditional external dependencies."""
|
232
233
|
|
233
234
|
class ExternalDependency:
|
234
|
-
_EXT_DEPENDENCIES: ClassVar[
|
235
|
+
_EXT_DEPENDENCIES: ClassVar[ExternalDependencies] = [{"name": "afni"}]
|
235
236
|
|
236
237
|
class CorrectMixer(PipelineStepMixin):
|
237
238
|
"""Test class for validation."""
|
238
239
|
|
239
|
-
_CONDITIONAL_DEPENDENCIES: ClassVar[
|
240
|
-
List[Dict[str, Union[str, Type]]]
|
241
|
-
] = [
|
240
|
+
_CONDITIONAL_DEPENDENCIES: ClassVar[ConditionalDependencies] = [
|
242
241
|
{
|
243
242
|
"using": "afni",
|
244
243
|
"depends_on": ExternalDependency,
|
@@ -247,13 +246,13 @@ def test_PipelineStepMixin_correct_conditional_ext_dependencies() -> None:
|
|
247
246
|
|
248
247
|
using = "afni"
|
249
248
|
|
250
|
-
def validate_input(self, input:
|
249
|
+
def validate_input(self, input: list[str]) -> list[str]:
|
251
250
|
return input
|
252
251
|
|
253
252
|
def get_output_type(self, input_type: str) -> str:
|
254
253
|
return input_type
|
255
254
|
|
256
|
-
def _fit_transform(self, input:
|
255
|
+
def _fit_transform(self, input: dict[str, dict]) -> dict[str, dict]:
|
257
256
|
return {"input": input}
|
258
257
|
|
259
258
|
mixer = CorrectMixer()
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# Synchon Mandal <s.mandal@fz-juelich.de>
|
5
5
|
# License: AGPL
|
6
6
|
|
7
|
-
from typing import
|
7
|
+
from typing import Union
|
8
8
|
|
9
9
|
import pytest
|
10
10
|
|
@@ -21,10 +21,10 @@ from junifer.pipeline.update_meta_mixin import UpdateMetaMixin
|
|
21
21
|
],
|
22
22
|
)
|
23
23
|
def test_UpdateMetaMixin(
|
24
|
-
input:
|
24
|
+
input: dict,
|
25
25
|
step_name: str,
|
26
|
-
dependencies: Union[
|
27
|
-
expected:
|
26
|
+
dependencies: Union[set, list, str, None],
|
27
|
+
expected: set,
|
28
28
|
) -> None:
|
29
29
|
"""Test UpdateMetaMixin.
|
30
30
|
|
@@ -102,3 +102,46 @@ def test_workdir_manager_get_and_delete_tempdir(tmp_path: Path) -> None:
|
|
102
102
|
workdir_mgr._cleanup()
|
103
103
|
# Should remove temporary directory
|
104
104
|
assert workdir_mgr.root_tempdir is None
|
105
|
+
|
106
|
+
|
107
|
+
def test_workdir_manager_no_cleanup(tmp_path: Path) -> None:
|
108
|
+
"""Test WorkDirManager correctly bypasses cleanup.
|
109
|
+
|
110
|
+
Parameters
|
111
|
+
----------
|
112
|
+
tmp_path : pathlib.Path
|
113
|
+
The path to the test directory.
|
114
|
+
|
115
|
+
"""
|
116
|
+
workdir_mgr = WorkDirManager(cleanup=False)
|
117
|
+
workdir_mgr.workdir = tmp_path
|
118
|
+
# Check no root temporary directory
|
119
|
+
assert workdir_mgr.root_tempdir is None
|
120
|
+
|
121
|
+
tempdir = workdir_mgr.get_tempdir()
|
122
|
+
assert tempdir.exists()
|
123
|
+
# Should create a temporary directory
|
124
|
+
assert workdir_mgr.root_tempdir is not None
|
125
|
+
|
126
|
+
workdir_mgr.delete_tempdir(tempdir)
|
127
|
+
workdir_mgr._cleanup()
|
128
|
+
|
129
|
+
# Should remove temporary directory
|
130
|
+
assert workdir_mgr.root_tempdir is None
|
131
|
+
# But the temporary directory should still exist
|
132
|
+
assert tempdir.exists()
|
133
|
+
|
134
|
+
# Now the same but for the element directory
|
135
|
+
|
136
|
+
# Check no element directory
|
137
|
+
assert workdir_mgr.elementdir is None
|
138
|
+
|
139
|
+
tempdir = workdir_mgr.get_element_tempdir()
|
140
|
+
# Should create a temporary directory
|
141
|
+
assert workdir_mgr.elementdir is not None
|
142
|
+
|
143
|
+
workdir_mgr.cleanup_elementdir()
|
144
|
+
# Should remove temporary directory
|
145
|
+
assert workdir_mgr.elementdir is None
|
146
|
+
# But the temporary directory should still exist
|
147
|
+
assert tempdir.exists()
|
@@ -4,7 +4,7 @@
|
|
4
4
|
# Synchon Mandal <s.mandal@fz-juelich.de>
|
5
5
|
# License: AGPL
|
6
6
|
|
7
|
-
from typing import
|
7
|
+
from typing import Union
|
8
8
|
|
9
9
|
|
10
10
|
__all__ = ["UpdateMetaMixin"]
|
@@ -15,14 +15,14 @@ class UpdateMetaMixin:
|
|
15
15
|
|
16
16
|
def update_meta(
|
17
17
|
self,
|
18
|
-
input:
|
18
|
+
input: Union[dict, list[dict]],
|
19
19
|
step_name: str,
|
20
20
|
) -> None:
|
21
21
|
"""Update metadata.
|
22
22
|
|
23
23
|
Parameters
|
24
24
|
----------
|
25
|
-
input : dict
|
25
|
+
input : dict or list of dict
|
26
26
|
The data object to update.
|
27
27
|
step_name : str
|
28
28
|
The name of the pipeline step.
|
@@ -36,17 +36,21 @@ class UpdateMetaMixin:
|
|
36
36
|
for k, v in vars(self).items():
|
37
37
|
if not k.startswith("_"):
|
38
38
|
t_meta[k] = v
|
39
|
-
#
|
40
|
-
if
|
41
|
-
input
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
39
|
+
# Conditional for list dtype vals like Warp
|
40
|
+
if not isinstance(input, list):
|
41
|
+
input = [input]
|
42
|
+
for entry in input:
|
43
|
+
# Add "meta" to the step's entry's local context dict
|
44
|
+
if "meta" not in entry:
|
45
|
+
entry["meta"] = {}
|
46
|
+
# Add step name
|
47
|
+
entry["meta"][step_name] = t_meta
|
48
|
+
# Add step dependencies
|
49
|
+
if "dependencies" not in entry["meta"]:
|
50
|
+
entry["meta"]["dependencies"] = set()
|
51
|
+
# Update step dependencies
|
52
|
+
dependencies = getattr(self, "_DEPENDENCIES", set())
|
53
|
+
if dependencies is not None:
|
54
|
+
if not isinstance(dependencies, (set, list)):
|
55
|
+
dependencies = {dependencies}
|
56
|
+
entry["meta"]["dependencies"].update(dependencies)
|
junifer/pipeline/utils.py
CHANGED
@@ -5,7 +5,7 @@
|
|
5
5
|
# License: AGPL
|
6
6
|
|
7
7
|
import subprocess
|
8
|
-
from typing import Any,
|
8
|
+
from typing import Any, Optional
|
9
9
|
|
10
10
|
from junifer.utils.logging import raise_error, warn_with_log
|
11
11
|
|
@@ -71,7 +71,7 @@ def check_ext_dependencies(
|
|
71
71
|
return found
|
72
72
|
|
73
73
|
|
74
|
-
def _check_afni(commands: Optional[
|
74
|
+
def _check_afni(commands: Optional[list[str]] = None) -> bool:
|
75
75
|
"""Check if AFNI is present in the system.
|
76
76
|
|
77
77
|
Parameters
|
@@ -131,7 +131,7 @@ def _check_afni(commands: Optional[List[str]] = None) -> bool:
|
|
131
131
|
return afni_found
|
132
132
|
|
133
133
|
|
134
|
-
def _check_fsl(commands: Optional[
|
134
|
+
def _check_fsl(commands: Optional[list[str]] = None) -> bool:
|
135
135
|
"""Check if FSL is present in the system.
|
136
136
|
|
137
137
|
Parameters
|
@@ -193,7 +193,7 @@ def _check_fsl(commands: Optional[List[str]] = None) -> bool:
|
|
193
193
|
return fsl_found
|
194
194
|
|
195
195
|
|
196
|
-
def _check_ants(commands: Optional[
|
196
|
+
def _check_ants(commands: Optional[list[str]] = None) -> bool:
|
197
197
|
"""Check if ANTs is present in the system.
|
198
198
|
|
199
199
|
Parameters
|
@@ -237,7 +237,7 @@ def _check_ants(commands: Optional[List[str]] = None) -> bool:
|
|
237
237
|
shell=True, # is unsafe but kept for resolution via PATH
|
238
238
|
check=False,
|
239
239
|
)
|
240
|
-
command_found = command_process.returncode ==
|
240
|
+
command_found = command_process.returncode == 1
|
241
241
|
commands_found_results[command] = (
|
242
242
|
"found" if command_found else "not found"
|
243
243
|
)
|
@@ -253,7 +253,7 @@ def _check_ants(commands: Optional[List[str]] = None) -> bool:
|
|
253
253
|
return ants_found
|
254
254
|
|
255
255
|
|
256
|
-
def _check_freesurfer(commands: Optional[
|
256
|
+
def _check_freesurfer(commands: Optional[list[str]] = None) -> bool:
|
257
257
|
"""Check if FreeSurfer is present in the system.
|
258
258
|
|
259
259
|
Parameters
|