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
|
@@ -3,9 +3,19 @@
|
|
|
3
3
|
# Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
|
|
4
4
|
# License: AGPL
|
|
5
5
|
|
|
6
|
+
import nibabel as nib
|
|
7
|
+
import numpy as np
|
|
8
|
+
import pandas as pd
|
|
9
|
+
import pytest
|
|
10
|
+
from numpy.testing import assert_array_equal
|
|
11
|
+
from pandas.testing import assert_frame_equal
|
|
12
|
+
|
|
6
13
|
from junifer.testing.datagrabbers import PartlyCloudyTestingDataGrabber
|
|
7
14
|
|
|
8
15
|
|
|
16
|
+
pytestmark = pytest.mark.external
|
|
17
|
+
|
|
18
|
+
|
|
9
19
|
def test_PartlyCloudyTestingDataGrabber() -> None:
|
|
10
20
|
"""Test PartlyCloudyTestingDataGrabber."""
|
|
11
21
|
expected_elements = [
|
|
@@ -38,3 +48,45 @@ def test_PartlyCloudyTestingDataGrabber() -> None:
|
|
|
38
48
|
out = dg["sub-01"]
|
|
39
49
|
assert "format" in out["BOLD"]["confounds"]
|
|
40
50
|
assert "fmriprep" == out["BOLD"]["confounds"]["format"]
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
@pytest.mark.parametrize("reduce_confounds", [True, False])
|
|
54
|
+
def test_PartlyCloudyTestingDataGrabber_n_timepoints(
|
|
55
|
+
reduce_confounds: bool,
|
|
56
|
+
) -> None:
|
|
57
|
+
"""Test PartlyCloudyTestingDataGrabber with fewer timepoints.
|
|
58
|
+
|
|
59
|
+
Parameters
|
|
60
|
+
----------
|
|
61
|
+
reduce_confounds : bool
|
|
62
|
+
The parametrized confounds reduction.
|
|
63
|
+
|
|
64
|
+
"""
|
|
65
|
+
with PartlyCloudyTestingDataGrabber(
|
|
66
|
+
reduce_confounds=reduce_confounds
|
|
67
|
+
) as dg:
|
|
68
|
+
full = dg["sub-01"]["BOLD"]
|
|
69
|
+
with PartlyCloudyTestingDataGrabber(
|
|
70
|
+
reduce_confounds=reduce_confounds, n_timepoints=50
|
|
71
|
+
) as dg:
|
|
72
|
+
out = dg["sub-01"]["BOLD"]
|
|
73
|
+
|
|
74
|
+
full_img = nib.load(full["path"])
|
|
75
|
+
out_img = nib.load(out["path"])
|
|
76
|
+
assert out_img.shape == (*full_img.shape[:3], 50)
|
|
77
|
+
assert_array_equal(
|
|
78
|
+
np.asanyarray(out_img.dataobj),
|
|
79
|
+
np.asanyarray(full_img.dataobj[..., :50]),
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
full_confounds = pd.read_csv(full["confounds"]["path"], sep="\t")
|
|
83
|
+
out_confounds = pd.read_csv(out["confounds"]["path"], sep="\t")
|
|
84
|
+
assert out_confounds.shape == (50, full_confounds.shape[1])
|
|
85
|
+
assert_frame_equal(out_confounds, full_confounds.iloc[:50])
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def test_PartlyCloudyTestingDataGrabber_n_subjects() -> None:
|
|
89
|
+
"""Test PartlyCloudyTestingDataGrabber with fewer subjects."""
|
|
90
|
+
with PartlyCloudyTestingDataGrabber(n_subjects=3) as dg:
|
|
91
|
+
assert dg.get_elements() == ["sub-01", "sub-02", "sub-03"]
|
|
92
|
+
assert dg["sub-03"]["BOLD"]["path"].exists()
|
|
@@ -3,9 +3,15 @@
|
|
|
3
3
|
# Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
|
|
4
4
|
# License: AGPL
|
|
5
5
|
|
|
6
|
+
import nibabel as nib
|
|
7
|
+
import pytest
|
|
8
|
+
|
|
6
9
|
from junifer.testing.datagrabbers import SPMAuditoryTestingDataGrabber
|
|
7
10
|
|
|
8
11
|
|
|
12
|
+
pytestmark = pytest.mark.external
|
|
13
|
+
|
|
14
|
+
|
|
9
15
|
def test_SPMAuditoryTestingDataGrabber() -> None:
|
|
10
16
|
"""Test SPMAuditoryTestingDataGrabber."""
|
|
11
17
|
expected_elements = [
|
|
@@ -31,3 +37,13 @@ def test_SPMAuditoryTestingDataGrabber() -> None:
|
|
|
31
37
|
assert "T1w" in out
|
|
32
38
|
assert out["T1w"]["path"].exists()
|
|
33
39
|
assert out["T1w"]["path"].is_file()
|
|
40
|
+
|
|
41
|
+
assert nib.load(out["BOLD"]["path"]).shape == (64, 64, 64, 84)
|
|
42
|
+
assert nib.load(out["T1w"]["path"]).shape == (256, 256, 54)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def test_SPMAuditoryTestingDataGrabber_n_timepoints() -> None:
|
|
46
|
+
"""Test SPMAuditoryTestingDataGrabber with fewer timepoints."""
|
|
47
|
+
with SPMAuditoryTestingDataGrabber(n_timepoints=10) as dg:
|
|
48
|
+
out = dg["sub001"]
|
|
49
|
+
assert nib.load(out["BOLD"]["path"]).shape == (64, 64, 64, 10)
|
|
@@ -5,12 +5,43 @@
|
|
|
5
5
|
# License: AGPL
|
|
6
6
|
|
|
7
7
|
from junifer.pipeline import PipelineComponentRegistry
|
|
8
|
+
from junifer.testing.datagrabbers import (
|
|
9
|
+
ADHDTestingDataGrabber,
|
|
10
|
+
OasisVBMTestingDataGrabber,
|
|
11
|
+
PartlyCloudyTestingDataGrabber,
|
|
12
|
+
SPMAuditoryTestingDataGrabber,
|
|
13
|
+
UCLACNPVBMTestingDataGrabber,
|
|
14
|
+
)
|
|
8
15
|
|
|
9
16
|
|
|
10
17
|
def test_testing_registry() -> None:
|
|
11
18
|
"""Test testing registry."""
|
|
19
|
+
for dg in [
|
|
20
|
+
ADHDTestingDataGrabber,
|
|
21
|
+
OasisVBMTestingDataGrabber,
|
|
22
|
+
SPMAuditoryTestingDataGrabber,
|
|
23
|
+
PartlyCloudyTestingDataGrabber,
|
|
24
|
+
UCLACNPVBMTestingDataGrabber,
|
|
25
|
+
]:
|
|
26
|
+
PipelineComponentRegistry().register(
|
|
27
|
+
step="datagrabber",
|
|
28
|
+
klass=dg,
|
|
29
|
+
)
|
|
12
30
|
assert {
|
|
31
|
+
"ADHDTestingDataGrabber",
|
|
13
32
|
"OasisVBMTestingDataGrabber",
|
|
14
33
|
"SPMAuditoryTestingDataGrabber",
|
|
15
34
|
"PartlyCloudyTestingDataGrabber",
|
|
35
|
+
"UCLACNPVBMTestingDataGrabber",
|
|
16
36
|
}.issubset(set(PipelineComponentRegistry().step_components("datagrabber")))
|
|
37
|
+
for dg in [
|
|
38
|
+
ADHDTestingDataGrabber,
|
|
39
|
+
OasisVBMTestingDataGrabber,
|
|
40
|
+
SPMAuditoryTestingDataGrabber,
|
|
41
|
+
PartlyCloudyTestingDataGrabber,
|
|
42
|
+
UCLACNPVBMTestingDataGrabber,
|
|
43
|
+
]:
|
|
44
|
+
PipelineComponentRegistry().deregister(
|
|
45
|
+
step="datagrabber",
|
|
46
|
+
klass=dg,
|
|
47
|
+
)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
"""Provide tests for testing utils."""
|
|
2
|
+
|
|
3
|
+
# Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
|
|
4
|
+
# License: AGPL
|
|
5
|
+
|
|
6
|
+
import pytest
|
|
7
|
+
|
|
8
|
+
from junifer.testing import config_override
|
|
9
|
+
from junifer.utils import config
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def test_config_override_unset() -> None:
|
|
13
|
+
"""Test config_override deletes a previously unset key."""
|
|
14
|
+
assert config.get("testing.override") is None
|
|
15
|
+
with config_override("testing.override", True):
|
|
16
|
+
assert config.get("testing.override") is True
|
|
17
|
+
assert "testing.override" not in config._config
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def test_config_override_restore() -> None:
|
|
21
|
+
"""Test config_override restores a previously set value."""
|
|
22
|
+
config.set("testing.override", 1)
|
|
23
|
+
try:
|
|
24
|
+
with config_override("testing.override", 2):
|
|
25
|
+
assert config.get("testing.override") == 2
|
|
26
|
+
assert config.get("testing.override") == 1
|
|
27
|
+
finally:
|
|
28
|
+
config.delete("testing.override")
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def test_config_override_error() -> None:
|
|
32
|
+
"""Test config_override restores the state on error."""
|
|
33
|
+
with pytest.raises(RuntimeError), config_override("testing.override", 3):
|
|
34
|
+
raise RuntimeError()
|
|
35
|
+
assert "testing.override" not in config._config
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""Provide tests for UCLACNPVBMTestingDataGrabber."""
|
|
2
|
+
|
|
3
|
+
# Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
|
|
4
|
+
# License: AGPL
|
|
5
|
+
|
|
6
|
+
import nibabel as nib
|
|
7
|
+
import numpy as np
|
|
8
|
+
import pytest
|
|
9
|
+
from numpy.testing import assert_array_almost_equal
|
|
10
|
+
from templateflow import api as tflow
|
|
11
|
+
|
|
12
|
+
from junifer.testing.datagrabbers import UCLACNPVBMTestingDataGrabber
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
pytestmark = pytest.mark.external
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def test_UCLACNPVBMTestingDataGrabber() -> None:
|
|
19
|
+
"""Test UCLACNPVBMTestingDataGrabber."""
|
|
20
|
+
with UCLACNPVBMTestingDataGrabber() as dg:
|
|
21
|
+
elements = dg.get_elements()
|
|
22
|
+
assert len(elements) == 10
|
|
23
|
+
out = dg[elements[0]]
|
|
24
|
+
assert "VBM_GM" in out
|
|
25
|
+
assert out["VBM_GM"]["path"].is_file()
|
|
26
|
+
assert out["VBM_GM"]["space"] == "MNI152NLin2009cAsym"
|
|
27
|
+
|
|
28
|
+
# Resampled to the templateflow grid, so templates and masks do not
|
|
29
|
+
# need resampling
|
|
30
|
+
img = nib.load(out["VBM_GM"]["path"])
|
|
31
|
+
template = nib.load(
|
|
32
|
+
tflow.get(
|
|
33
|
+
"MNI152NLin2009cAsym",
|
|
34
|
+
resolution=2,
|
|
35
|
+
suffix="T1w",
|
|
36
|
+
desc=None,
|
|
37
|
+
extension="nii.gz",
|
|
38
|
+
)
|
|
39
|
+
)
|
|
40
|
+
assert img.shape == template.shape[:3]
|
|
41
|
+
assert_array_almost_equal(img.affine, template.affine)
|
|
42
|
+
|
|
43
|
+
participants = dg.get_participants()
|
|
44
|
+
assert list(participants.index) == elements
|
|
45
|
+
assert {"age", "gender"} <= set(participants.columns)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def test_UCLACNPVBMTestingDataGrabber_native() -> None:
|
|
49
|
+
"""Test UCLACNPVBMTestingDataGrabber at the native resolution."""
|
|
50
|
+
with UCLACNPVBMTestingDataGrabber(resolution=1) as dg:
|
|
51
|
+
out = dg[dg.get_elements()[0]]
|
|
52
|
+
# No resampling at the native resolution
|
|
53
|
+
assert out["VBM_GM"]["path"].name.endswith("_probtissue.nii.gz")
|
|
54
|
+
assert nib.load(out["VBM_GM"]["path"]).shape == (193, 229, 193)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def test_UCLACNPVBMTestingDataGrabber_resample() -> None:
|
|
58
|
+
"""Test UCLACNPVBMTestingDataGrabber resampling to a new resolution."""
|
|
59
|
+
with UCLACNPVBMTestingDataGrabber(resolution=4) as dg:
|
|
60
|
+
element = dg.get_elements()[0]
|
|
61
|
+
# Remove the cached map so it is resampled again (the CI image only
|
|
62
|
+
# has the default resolution)
|
|
63
|
+
native = dg._paths[element]
|
|
64
|
+
cached = native.with_name(
|
|
65
|
+
native.name.replace(".nii.gz", "_res-4mm.nii")
|
|
66
|
+
)
|
|
67
|
+
cached.unlink(missing_ok=True)
|
|
68
|
+
|
|
69
|
+
out = dg[element]
|
|
70
|
+
assert out["VBM_GM"]["path"] == cached
|
|
71
|
+
img = nib.load(cached)
|
|
72
|
+
assert img.shape == (49, 58, 49)
|
|
73
|
+
assert img.get_data_dtype() == np.float32
|
|
74
|
+
expected_affine = np.diag([4.0, 4.0, 4.0, 1.0])
|
|
75
|
+
expected_affine[:3, 3] = [-97.5, -133.5, -79.5]
|
|
76
|
+
assert_array_almost_equal(img.affine, expected_affine)
|
|
77
|
+
|
|
78
|
+
# Cached, so it is not resampled again
|
|
79
|
+
mtime = cached.stat().st_mtime_ns
|
|
80
|
+
assert dg[element]["VBM_GM"]["path"] == cached
|
|
81
|
+
assert cached.stat().st_mtime_ns == mtime
|
junifer/testing/utils.py
CHANGED
|
@@ -3,10 +3,15 @@
|
|
|
3
3
|
# Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
|
|
4
4
|
# License: AGPL
|
|
5
5
|
|
|
6
|
+
from collections.abc import Generator
|
|
7
|
+
from contextlib import contextmanager
|
|
6
8
|
from pathlib import Path
|
|
7
9
|
|
|
10
|
+
from ..utils import config
|
|
11
|
+
from ..utils._config import ConfigVal
|
|
8
12
|
|
|
9
|
-
|
|
13
|
+
|
|
14
|
+
__all__ = ["config_override", "get_testing_data"]
|
|
10
15
|
|
|
11
16
|
|
|
12
17
|
def get_testing_data(fname: str) -> Path:
|
|
@@ -27,3 +32,30 @@ def get_testing_data(fname: str) -> Path:
|
|
|
27
32
|
if not t_path.exists():
|
|
28
33
|
raise FileNotFoundError(f"File {fname} not found in testing data")
|
|
29
34
|
return t_path.resolve()
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
@contextmanager
|
|
38
|
+
def config_override(key: str, val: ConfigVal) -> Generator[None, None, None]:
|
|
39
|
+
"""Temporarily set a configuration parameter.
|
|
40
|
+
|
|
41
|
+
The previous state is restored on exit: the previous value if the key
|
|
42
|
+
was set, otherwise the key is deleted.
|
|
43
|
+
|
|
44
|
+
Parameters
|
|
45
|
+
----------
|
|
46
|
+
key : str
|
|
47
|
+
The configuration key to set.
|
|
48
|
+
val : bool or int or float
|
|
49
|
+
The value to set ``key`` to.
|
|
50
|
+
|
|
51
|
+
"""
|
|
52
|
+
missing = object()
|
|
53
|
+
prev = config.get(key, missing)
|
|
54
|
+
config.set(key, val)
|
|
55
|
+
try:
|
|
56
|
+
yield
|
|
57
|
+
finally:
|
|
58
|
+
if prev is missing:
|
|
59
|
+
config.delete(key)
|
|
60
|
+
else:
|
|
61
|
+
config.set(key, prev)
|
junifer/tests/test_stats.py
CHANGED
|
@@ -3,8 +3,6 @@
|
|
|
3
3
|
# Authors: Synchon Mandal <s.mandal@fz-juelich.de>
|
|
4
4
|
# License: AGPL
|
|
5
5
|
|
|
6
|
-
from typing import Optional
|
|
7
|
-
|
|
8
6
|
import numpy as np
|
|
9
7
|
import pytest
|
|
10
8
|
from numpy.testing import assert_array_equal
|
|
@@ -25,7 +23,7 @@ from junifer.stats import count, get_aggfunc_by_name, select, winsorized_mean
|
|
|
25
23
|
("mode", {"keepdims": True}),
|
|
26
24
|
],
|
|
27
25
|
)
|
|
28
|
-
def test_get_aggfunc_by_name(name: str, params:
|
|
26
|
+
def test_get_aggfunc_by_name(name: str, params: dict | None) -> None:
|
|
29
27
|
"""Test aggregation function retrieval by name.
|
|
30
28
|
|
|
31
29
|
Parameters
|
|
@@ -41,8 +39,6 @@ def test_get_aggfunc_by_name(name: str, params: Optional[dict]) -> None:
|
|
|
41
39
|
|
|
42
40
|
def test_get_aggfunc_by_name_errors() -> None:
|
|
43
41
|
"""Test aggregation function retrieval using wrong name."""
|
|
44
|
-
with pytest.raises(ValueError, match=r"unknown. Please provide any of"):
|
|
45
|
-
get_aggfunc_by_name(name="invalid", func_params=None)
|
|
46
42
|
|
|
47
43
|
with pytest.raises(ValueError, match=r"list of limits"):
|
|
48
44
|
get_aggfunc_by_name(name="winsorized_mean", func_params=None)
|
junifer/typing/__init__.pyi
CHANGED
|
@@ -12,6 +12,7 @@ __all__ = [
|
|
|
12
12
|
"MarkerInOutMappings",
|
|
13
13
|
"DataGrabberPatterns",
|
|
14
14
|
"ConfigVal",
|
|
15
|
+
"SpaceLike",
|
|
15
16
|
"Element",
|
|
16
17
|
"Elements",
|
|
17
18
|
]
|
|
@@ -30,6 +31,7 @@ from ._typing import (
|
|
|
30
31
|
MarkerInOutMappings,
|
|
31
32
|
DataGrabberPatterns,
|
|
32
33
|
ConfigVal,
|
|
34
|
+
SpaceLike,
|
|
33
35
|
Element,
|
|
34
36
|
Elements,
|
|
35
37
|
)
|
junifer/typing/_typing.py
CHANGED
|
@@ -3,7 +3,16 @@
|
|
|
3
3
|
# Authors: Synchon Mandal <s.mandal@fz-juelich.de>
|
|
4
4
|
# License: AGPL
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
import sys
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
if sys.version_info < (3, 12): # pragma: no cover
|
|
10
|
+
from typing_extensions import TypedDict
|
|
11
|
+
else:
|
|
12
|
+
from typing import TypedDict
|
|
13
|
+
|
|
14
|
+
from collections.abc import Sequence
|
|
15
|
+
from enum import Enum
|
|
7
16
|
from typing import (
|
|
8
17
|
TYPE_CHECKING,
|
|
9
18
|
Union,
|
|
@@ -12,11 +21,12 @@ from typing import (
|
|
|
12
21
|
|
|
13
22
|
if TYPE_CHECKING:
|
|
14
23
|
from ..data import BasePipelineDataRegistry
|
|
15
|
-
from ..datagrabber import BaseDataGrabber
|
|
24
|
+
from ..datagrabber import BaseDataGrabber, DataType
|
|
16
25
|
from ..datareader import DefaultDataReader
|
|
17
26
|
from ..markers import BaseMarker
|
|
27
|
+
from ..pipeline import BaseDataDumpAsset, ExtDep
|
|
18
28
|
from ..preprocess import BasePreprocessor
|
|
19
|
-
from ..storage import BaseFeatureStorage
|
|
29
|
+
from ..storage import BaseFeatureStorage, StorageType
|
|
20
30
|
|
|
21
31
|
|
|
22
32
|
__all__ = [
|
|
@@ -34,11 +44,22 @@ __all__ = [
|
|
|
34
44
|
"MarkerLike",
|
|
35
45
|
"PipelineComponent",
|
|
36
46
|
"PreprocessorLike",
|
|
47
|
+
"SpaceLike",
|
|
37
48
|
"StorageLike",
|
|
38
49
|
]
|
|
39
50
|
|
|
40
51
|
|
|
41
|
-
|
|
52
|
+
class ExternalDependency(TypedDict):
|
|
53
|
+
name: "ExtDep"
|
|
54
|
+
commands: list[str]
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class ConditionalDependency(TypedDict):
|
|
58
|
+
using: object
|
|
59
|
+
depends_on: list[object]
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
DataDumpAssetLike = type["BaseDataDumpAsset"]
|
|
42
63
|
DataRegistryLike = type["BasePipelineDataRegistry"]
|
|
43
64
|
DataGrabberLike = type["BaseDataGrabber"]
|
|
44
65
|
PreprocessorLike = type["BasePreprocessor"]
|
|
@@ -52,20 +73,14 @@ PipelineComponent = Union[
|
|
|
52
73
|
"StorageLike",
|
|
53
74
|
]
|
|
54
75
|
Dependencies = set[str]
|
|
55
|
-
ConditionalDependencies =
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
Sequence[str],
|
|
62
|
-
Sequence[PipelineComponent],
|
|
63
|
-
],
|
|
64
|
-
]
|
|
76
|
+
ConditionalDependencies = list[ConditionalDependency]
|
|
77
|
+
ExternalDependencies = list[ExternalDependency]
|
|
78
|
+
MarkerInOutMappings = dict["DataType", dict[str, "StorageType"]]
|
|
79
|
+
DataGrabberPatterns = dict[
|
|
80
|
+
str,
|
|
81
|
+
dict[str, dict[str, str] | str] | dict[str, str] | list[dict[str, str]],
|
|
65
82
|
]
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
ConfigVal = Union[bool, int, float, str]
|
|
70
|
-
Element = Union[str, tuple[str, ...]]
|
|
83
|
+
ConfigVal = bool | int | float | str
|
|
84
|
+
SpaceLike = str | Enum
|
|
85
|
+
Element = str | tuple[str, ...]
|
|
71
86
|
Elements = Sequence[Element]
|
junifer/typing/py.typed
ADDED
|
File without changes
|
junifer/utils/__init__.pyi
CHANGED
|
@@ -7,6 +7,9 @@ __all__ = [
|
|
|
7
7
|
"warn_with_log",
|
|
8
8
|
"run_ext_cmd",
|
|
9
9
|
"deep_update",
|
|
10
|
+
"ensure_list",
|
|
11
|
+
"ensure_list_or_none",
|
|
12
|
+
"check_standardize",
|
|
10
13
|
"yaml",
|
|
11
14
|
"ConfigManager",
|
|
12
15
|
]
|
|
@@ -14,5 +17,11 @@ __all__ = [
|
|
|
14
17
|
from .fs import make_executable
|
|
15
18
|
from .logging import configure_logging, logger, raise_error, warn_with_log
|
|
16
19
|
from ._config import config, ConfigManager
|
|
17
|
-
from .helpers import
|
|
20
|
+
from .helpers import (
|
|
21
|
+
run_ext_cmd,
|
|
22
|
+
deep_update,
|
|
23
|
+
ensure_list,
|
|
24
|
+
ensure_list_or_none,
|
|
25
|
+
check_standardize,
|
|
26
|
+
)
|
|
18
27
|
from ._yaml import yaml
|
junifer/utils/_config.py
CHANGED
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
# License: AGPL
|
|
6
6
|
|
|
7
7
|
import os
|
|
8
|
-
from typing import Optional
|
|
9
8
|
|
|
10
9
|
from ..typing import ConfigVal
|
|
11
10
|
from .logging import logger
|
|
@@ -61,7 +60,7 @@ class ConfigManager(metaclass=Singleton):
|
|
|
61
60
|
)
|
|
62
61
|
self._config[var_name] = var_value
|
|
63
62
|
|
|
64
|
-
def get(self, key: str, default:
|
|
63
|
+
def get(self, key: str, default: ConfigVal | None = None) -> ConfigVal:
|
|
65
64
|
"""Get configuration parameter.
|
|
66
65
|
|
|
67
66
|
Parameters
|
junifer/utils/helpers.py
CHANGED
|
@@ -6,14 +6,22 @@
|
|
|
6
6
|
import collections.abc
|
|
7
7
|
import subprocess
|
|
8
8
|
import sys
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from typing import Any
|
|
9
11
|
|
|
10
12
|
from .logging import logger, raise_error
|
|
11
13
|
|
|
12
14
|
|
|
13
|
-
__all__ = [
|
|
15
|
+
__all__ = [
|
|
16
|
+
"check_standardize",
|
|
17
|
+
"deep_update",
|
|
18
|
+
"ensure_list",
|
|
19
|
+
"ensure_list_or_none",
|
|
20
|
+
"run_ext_cmd",
|
|
21
|
+
]
|
|
14
22
|
|
|
15
23
|
|
|
16
|
-
def run_ext_cmd(name: str, cmd: list[str]) -> None:
|
|
24
|
+
def run_ext_cmd(name: str, cmd: list[str], cwd: Path | None = None) -> None:
|
|
17
25
|
"""Run external command via subprocess.
|
|
18
26
|
|
|
19
27
|
Parameters
|
|
@@ -22,6 +30,10 @@ def run_ext_cmd(name: str, cmd: list[str]) -> None:
|
|
|
22
30
|
The name of the command.
|
|
23
31
|
cmd : list of str
|
|
24
32
|
The command to run as list of string.
|
|
33
|
+
cwd : pathlib.Path or None, optional
|
|
34
|
+
The directory to run the command in, e.g., for commands that write
|
|
35
|
+
extra files in the current directory. If None, the current directory
|
|
36
|
+
is used (default None).
|
|
25
37
|
|
|
26
38
|
Raises
|
|
27
39
|
------
|
|
@@ -40,6 +52,7 @@ def run_ext_cmd(name: str, cmd: list[str]) -> None:
|
|
|
40
52
|
stderr=subprocess.STDOUT,
|
|
41
53
|
shell=True, # needed for respecting $PATH
|
|
42
54
|
check=False,
|
|
55
|
+
cwd=cwd,
|
|
43
56
|
)
|
|
44
57
|
# Check for success or failure
|
|
45
58
|
if process.returncode == 0:
|
|
@@ -82,3 +95,56 @@ def deep_update(d: dict, u: dict) -> dict:
|
|
|
82
95
|
else:
|
|
83
96
|
d[k] = v
|
|
84
97
|
return d
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def ensure_list(value: Any) -> Any:
|
|
101
|
+
"""Ensure list."""
|
|
102
|
+
if not isinstance(value, list):
|
|
103
|
+
return [value]
|
|
104
|
+
else:
|
|
105
|
+
return value
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
def ensure_list_or_none(value: Any) -> Any:
|
|
109
|
+
"""Ensure list or None."""
|
|
110
|
+
if value is None:
|
|
111
|
+
return None
|
|
112
|
+
if not isinstance(value, list):
|
|
113
|
+
return [value]
|
|
114
|
+
else:
|
|
115
|
+
return value
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def check_standardize(value: Any) -> Any:
|
|
119
|
+
"""Check the value of a ``standardize`` parameter.
|
|
120
|
+
|
|
121
|
+
Booleans were replaced by the strategy names used by nilearn, so they
|
|
122
|
+
raise an error explaining the change instead of a generic validation
|
|
123
|
+
error.
|
|
124
|
+
|
|
125
|
+
Parameters
|
|
126
|
+
----------
|
|
127
|
+
value : Any
|
|
128
|
+
The value of the parameter.
|
|
129
|
+
|
|
130
|
+
Returns
|
|
131
|
+
-------
|
|
132
|
+
Any
|
|
133
|
+
The value of the parameter.
|
|
134
|
+
|
|
135
|
+
Raises
|
|
136
|
+
------
|
|
137
|
+
ValueError
|
|
138
|
+
If ``value`` is a boolean.
|
|
139
|
+
|
|
140
|
+
"""
|
|
141
|
+
if isinstance(value, bool):
|
|
142
|
+
raise_error(
|
|
143
|
+
"`standardize` does not accept booleans anymore, following "
|
|
144
|
+
"nilearn, which is removing them: True used to z-score with the "
|
|
145
|
+
"population standard deviation, while nilearn now z-scores with "
|
|
146
|
+
"the sample standard deviation ('zscore_sample'). Use "
|
|
147
|
+
"'zscore_sample' instead of True and None instead of False "
|
|
148
|
+
f"(got {value})."
|
|
149
|
+
)
|
|
150
|
+
return value
|
junifer/utils/logging.py
CHANGED
|
@@ -14,8 +14,17 @@ else:
|
|
|
14
14
|
|
|
15
15
|
import logging
|
|
16
16
|
import logging.config
|
|
17
|
+
import sys
|
|
17
18
|
import warnings
|
|
18
|
-
|
|
19
|
+
|
|
20
|
+
# Before Python 3.11, packages_distributions() only uses top_level.txt and
|
|
21
|
+
# misses packages that do not ship it
|
|
22
|
+
from importlib.metadata import (
|
|
23
|
+
PackageNotFoundError,
|
|
24
|
+
packages_distributions,
|
|
25
|
+
version,
|
|
26
|
+
)
|
|
27
|
+
from typing import NoReturn
|
|
19
28
|
from warnings import warn
|
|
20
29
|
|
|
21
30
|
import datalad
|
|
@@ -111,7 +120,8 @@ structlog.configure(
|
|
|
111
120
|
cache_logger_on_first_use=True,
|
|
112
121
|
)
|
|
113
122
|
|
|
114
|
-
|
|
123
|
+
_log = structlog.get_logger("junifer")
|
|
124
|
+
logger = _log.bind(pkg="utils")
|
|
115
125
|
|
|
116
126
|
# Remove datalad logger handlers to avoid duplicate logging
|
|
117
127
|
_datalad_lgr_hdlrs = datalad.log.lgr.handlers
|
|
@@ -150,6 +160,8 @@ def get_versions() -> dict:
|
|
|
150
160
|
The module names and corresponding versions.
|
|
151
161
|
|
|
152
162
|
"""
|
|
163
|
+
# Map top-level modules to their distributions
|
|
164
|
+
module_distributions = packages_distributions()
|
|
153
165
|
# Setup dictionary to track versions of modules
|
|
154
166
|
module_versions = {}
|
|
155
167
|
for name, module in sys.modules.copy().items():
|
|
@@ -157,8 +169,20 @@ def get_versions() -> dict:
|
|
|
157
169
|
# allowing ruamel.yaml
|
|
158
170
|
if "." in name and name != "ruamel.yaml":
|
|
159
171
|
continue
|
|
172
|
+
# Get version from distribution metadata, as some packages
|
|
173
|
+
# deprecated the module attribute (e.g. click, markupsafe)
|
|
174
|
+
vstring = None
|
|
175
|
+
for dist_name in module_distributions.get(name, []):
|
|
176
|
+
try:
|
|
177
|
+
vstring = version(dist_name)
|
|
178
|
+
break
|
|
179
|
+
except PackageNotFoundError:
|
|
180
|
+
continue
|
|
181
|
+
# Fallback to module attribute
|
|
182
|
+
if vstring is None:
|
|
183
|
+
vstring = getattr(module, "__version__", None)
|
|
160
184
|
# Get version or None as string
|
|
161
|
-
vstring = str(
|
|
185
|
+
vstring = str(vstring)
|
|
162
186
|
# Get module version
|
|
163
187
|
module_version = getattr(LooseVersion(vstring), "vstring", None)
|
|
164
188
|
module_versions[name] = module_version
|
|
@@ -210,8 +234,8 @@ def log_versions() -> None:
|
|
|
210
234
|
|
|
211
235
|
|
|
212
236
|
def configure_logging(
|
|
213
|
-
level:
|
|
214
|
-
level_datalad:
|
|
237
|
+
level: int | str = "WARNING",
|
|
238
|
+
level_datalad: int | str | None = None,
|
|
215
239
|
) -> None:
|
|
216
240
|
"""Configure the logging functionality.
|
|
217
241
|
|
|
@@ -246,7 +270,7 @@ def configure_logging(
|
|
|
246
270
|
def raise_error(
|
|
247
271
|
msg: str,
|
|
248
272
|
klass: type[Exception] = ValueError,
|
|
249
|
-
exception:
|
|
273
|
+
exception: Exception | None = None,
|
|
250
274
|
) -> NoReturn:
|
|
251
275
|
"""Raise error, but first log it.
|
|
252
276
|
|
|
@@ -268,7 +292,7 @@ def raise_error(
|
|
|
268
292
|
|
|
269
293
|
|
|
270
294
|
def warn_with_log(
|
|
271
|
-
msg: str, category:
|
|
295
|
+
msg: str, category: type[Warning] | None = RuntimeWarning
|
|
272
296
|
) -> None:
|
|
273
297
|
"""Warn, but first log it.
|
|
274
298
|
|