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
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
"""Provide tests for storing the same data more than once."""
|
|
2
|
+
|
|
3
|
+
# Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
|
|
4
|
+
# License: AGPL
|
|
5
|
+
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
import numpy as np
|
|
9
|
+
import pandas as pd
|
|
10
|
+
import pytest
|
|
11
|
+
|
|
12
|
+
from junifer.storage import HDF5FeatureStorage, SQLiteFeatureStorage
|
|
13
|
+
from junifer.storage.base import BaseFeatureStorage
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
# The storage types supported by each storage
|
|
17
|
+
_CASES = [
|
|
18
|
+
(klass, kind, single_output)
|
|
19
|
+
for klass, kinds in (
|
|
20
|
+
(
|
|
21
|
+
HDF5FeatureStorage,
|
|
22
|
+
[
|
|
23
|
+
"vector",
|
|
24
|
+
"matrix",
|
|
25
|
+
"timeseries",
|
|
26
|
+
"scalar_table",
|
|
27
|
+
"timeseries_2d",
|
|
28
|
+
],
|
|
29
|
+
),
|
|
30
|
+
(SQLiteFeatureStorage, ["vector", "matrix", "timeseries"]),
|
|
31
|
+
)
|
|
32
|
+
for kind in kinds
|
|
33
|
+
for single_output in (True, False)
|
|
34
|
+
]
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _data(kind: str, value: float) -> dict:
|
|
38
|
+
"""Get data of a storage type with a value.
|
|
39
|
+
|
|
40
|
+
Parameters
|
|
41
|
+
----------
|
|
42
|
+
kind : str
|
|
43
|
+
The storage type.
|
|
44
|
+
value : float
|
|
45
|
+
The value of the data.
|
|
46
|
+
|
|
47
|
+
Returns
|
|
48
|
+
-------
|
|
49
|
+
dict
|
|
50
|
+
The data and the other parameters to store it.
|
|
51
|
+
|
|
52
|
+
"""
|
|
53
|
+
names = {"col_names": ["a", "b"]}
|
|
54
|
+
if kind == "vector":
|
|
55
|
+
return {"data": np.full((1, 2), value), **names}
|
|
56
|
+
if kind == "matrix":
|
|
57
|
+
return {
|
|
58
|
+
"data": np.full((2, 2), value),
|
|
59
|
+
"row_names": ["r1", "r2"],
|
|
60
|
+
"matrix_kind": "full",
|
|
61
|
+
**names,
|
|
62
|
+
}
|
|
63
|
+
if kind == "timeseries":
|
|
64
|
+
return {"data": np.full((3, 2), value), **names}
|
|
65
|
+
if kind == "scalar_table":
|
|
66
|
+
return {
|
|
67
|
+
"data": np.full((2, 2), value),
|
|
68
|
+
"row_names": ["r1", "r2"],
|
|
69
|
+
"row_header_col_name": "feature",
|
|
70
|
+
**names,
|
|
71
|
+
}
|
|
72
|
+
return {
|
|
73
|
+
"data": np.full((3, 2, 2), value),
|
|
74
|
+
"row_names": ["r1", "r2"],
|
|
75
|
+
**names,
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def _store(
|
|
80
|
+
storage: BaseFeatureStorage,
|
|
81
|
+
kind: str,
|
|
82
|
+
element: dict,
|
|
83
|
+
value: float,
|
|
84
|
+
element_keys: list[str] | None = None,
|
|
85
|
+
) -> None:
|
|
86
|
+
"""Store data of an element being processed, as a marker does.
|
|
87
|
+
|
|
88
|
+
Parameters
|
|
89
|
+
----------
|
|
90
|
+
storage : BaseFeatureStorage
|
|
91
|
+
The storage.
|
|
92
|
+
kind : str
|
|
93
|
+
The storage type.
|
|
94
|
+
element : dict
|
|
95
|
+
The element being processed.
|
|
96
|
+
value : float
|
|
97
|
+
The value of the data.
|
|
98
|
+
element_keys : list of str or None, optional
|
|
99
|
+
The keys of the element that the data depends on. If None, all the
|
|
100
|
+
keys (default None).
|
|
101
|
+
|
|
102
|
+
"""
|
|
103
|
+
meta = {
|
|
104
|
+
"element": element,
|
|
105
|
+
"dependencies": set(),
|
|
106
|
+
"marker": {"name": "test"},
|
|
107
|
+
"type": "BOLD",
|
|
108
|
+
}
|
|
109
|
+
if element_keys is not None:
|
|
110
|
+
meta["_element_keys"] = element_keys
|
|
111
|
+
storage.store(kind=kind, meta=meta, **_data(kind, value))
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
def _read(
|
|
115
|
+
storage: BaseFeatureStorage, collect: bool = True
|
|
116
|
+
) -> tuple[pd.DataFrame, list[tuple]]:
|
|
117
|
+
"""Read the stored feature, collecting it first if needed.
|
|
118
|
+
|
|
119
|
+
Parameters
|
|
120
|
+
----------
|
|
121
|
+
storage : BaseFeatureStorage
|
|
122
|
+
The storage.
|
|
123
|
+
collect : bool, optional
|
|
124
|
+
Whether to collect the files of the elements first (default True).
|
|
125
|
+
|
|
126
|
+
Returns
|
|
127
|
+
-------
|
|
128
|
+
pandas.DataFrame
|
|
129
|
+
The feature.
|
|
130
|
+
list of tuple
|
|
131
|
+
The elements of the feature, without duplicates.
|
|
132
|
+
|
|
133
|
+
"""
|
|
134
|
+
if not storage.single_output and collect:
|
|
135
|
+
storage.collect()
|
|
136
|
+
reader = type(storage)(uri=storage.uri)
|
|
137
|
+
(md5,) = reader.list_features()
|
|
138
|
+
df = reader.read_df(feature_md5=md5)
|
|
139
|
+
# No repeated rows (the index has the element and, for some storage
|
|
140
|
+
# types, the rows of the data of an element)
|
|
141
|
+
assert not df.index.duplicated().any()
|
|
142
|
+
keys = [k for k in ("subject", "task") if k in df.index.names]
|
|
143
|
+
levels = [df.index.get_level_values(k) for k in keys]
|
|
144
|
+
elements = sorted(set(zip(*levels, strict=True)))
|
|
145
|
+
return df, elements
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
@pytest.mark.parametrize("klass, kind, single_output", _CASES)
|
|
149
|
+
def test_store_again(
|
|
150
|
+
tmp_path: Path, klass: type, kind: str, single_output: bool
|
|
151
|
+
) -> None:
|
|
152
|
+
"""Test storing the same element again does not change the storage.
|
|
153
|
+
|
|
154
|
+
Parameters
|
|
155
|
+
----------
|
|
156
|
+
tmp_path : pathlib.Path
|
|
157
|
+
The path to the test directory.
|
|
158
|
+
klass : type
|
|
159
|
+
The parametrized storage class.
|
|
160
|
+
kind : str
|
|
161
|
+
The parametrized storage type.
|
|
162
|
+
single_output : bool
|
|
163
|
+
The parametrized storage in a single file.
|
|
164
|
+
|
|
165
|
+
"""
|
|
166
|
+
storage = klass(uri=tmp_path / "out.db", single_output=single_output)
|
|
167
|
+
element = {"subject": "sub-01", "task": "rest"}
|
|
168
|
+
_store(storage, kind, element, 1)
|
|
169
|
+
# Already stored: skipped, even with other values
|
|
170
|
+
_store(storage, kind, element, 2)
|
|
171
|
+
df, elements = _read(storage)
|
|
172
|
+
assert elements == [("sub-01", "rest")]
|
|
173
|
+
assert (df.to_numpy() == 1).all()
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
@pytest.mark.parametrize("klass, kind, single_output", _CASES)
|
|
177
|
+
def test_store_element_of_data(
|
|
178
|
+
tmp_path: Path, klass: type, kind: str, single_output: bool
|
|
179
|
+
) -> None:
|
|
180
|
+
"""Test storing data that does not depend on all the element keys.
|
|
181
|
+
|
|
182
|
+
Parameters
|
|
183
|
+
----------
|
|
184
|
+
tmp_path : pathlib.Path
|
|
185
|
+
The path to the test directory.
|
|
186
|
+
klass : type
|
|
187
|
+
The parametrized storage class.
|
|
188
|
+
kind : str
|
|
189
|
+
The parametrized storage type.
|
|
190
|
+
single_output : bool
|
|
191
|
+
The parametrized storage in a single file.
|
|
192
|
+
|
|
193
|
+
"""
|
|
194
|
+
storage = klass(uri=tmp_path / "out.db", single_output=single_output)
|
|
195
|
+
# The data of a subject, the same when processing each of its tasks
|
|
196
|
+
for task in ("rest", "movie"):
|
|
197
|
+
element = {"subject": "sub-01", "task": task}
|
|
198
|
+
_store(storage, kind, element, 1, element_keys=["subject"])
|
|
199
|
+
if not single_output:
|
|
200
|
+
# One file for each element being processed
|
|
201
|
+
files = sorted(x.name for x in tmp_path.glob("*_out.db"))
|
|
202
|
+
assert files == [
|
|
203
|
+
"element_sub-01_movie_out.db",
|
|
204
|
+
"element_sub-01_rest_out.db",
|
|
205
|
+
]
|
|
206
|
+
df, elements = _read(storage)
|
|
207
|
+
assert elements == [("sub-01",)]
|
|
208
|
+
assert (df.to_numpy() == 1).all()
|
|
209
|
+
|
|
210
|
+
|
|
211
|
+
@pytest.mark.parametrize(
|
|
212
|
+
"klass, kind, single_output",
|
|
213
|
+
[case for case in _CASES if not case[2]],
|
|
214
|
+
)
|
|
215
|
+
def test_collect_again(
|
|
216
|
+
tmp_path: Path, klass: type, kind: str, single_output: bool
|
|
217
|
+
) -> None:
|
|
218
|
+
"""Test collecting again does not change the storage.
|
|
219
|
+
|
|
220
|
+
Parameters
|
|
221
|
+
----------
|
|
222
|
+
tmp_path : pathlib.Path
|
|
223
|
+
The path to the test directory.
|
|
224
|
+
klass : type
|
|
225
|
+
The parametrized storage class.
|
|
226
|
+
kind : str
|
|
227
|
+
The parametrized storage type.
|
|
228
|
+
single_output : bool
|
|
229
|
+
The parametrized storage in a single file.
|
|
230
|
+
|
|
231
|
+
"""
|
|
232
|
+
storage = klass(uri=tmp_path / "out.db", single_output=single_output)
|
|
233
|
+
for subject in ("sub-01", "sub-02"):
|
|
234
|
+
_store(storage, kind, {"subject": subject, "task": "rest"}, 1)
|
|
235
|
+
storage.collect()
|
|
236
|
+
_, elements = _read(storage)
|
|
237
|
+
assert elements == [("sub-01", "rest"), ("sub-02", "rest")]
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
@pytest.mark.parametrize("klass, kind, single_output", _CASES)
|
|
241
|
+
def test_store_trial_then_all(
|
|
242
|
+
tmp_path: Path, klass: type, kind: str, single_output: bool
|
|
243
|
+
) -> None:
|
|
244
|
+
"""Test storing some elements and then all the elements.
|
|
245
|
+
|
|
246
|
+
For example, running a few elements to test a configuration, and then
|
|
247
|
+
queueing all the elements with the same configuration.
|
|
248
|
+
|
|
249
|
+
Parameters
|
|
250
|
+
----------
|
|
251
|
+
tmp_path : pathlib.Path
|
|
252
|
+
The path to the test directory.
|
|
253
|
+
klass : type
|
|
254
|
+
The parametrized storage class.
|
|
255
|
+
kind : str
|
|
256
|
+
The parametrized storage type.
|
|
257
|
+
single_output : bool
|
|
258
|
+
The parametrized storage in a single file.
|
|
259
|
+
|
|
260
|
+
"""
|
|
261
|
+
storage = klass(uri=tmp_path / "out.db", single_output=single_output)
|
|
262
|
+
# Trial
|
|
263
|
+
_store(storage, kind, {"subject": "sub-01", "task": "rest"}, 1)
|
|
264
|
+
_read(storage)
|
|
265
|
+
# All the elements
|
|
266
|
+
for subject in ("sub-01", "sub-02"):
|
|
267
|
+
_store(storage, kind, {"subject": subject, "task": "rest"}, 2)
|
|
268
|
+
df, elements = _read(storage)
|
|
269
|
+
assert elements == [("sub-01", "rest"), ("sub-02", "rest")]
|
|
270
|
+
# The trial element keeps its values
|
|
271
|
+
sub01 = df.xs("sub-01", level="subject")
|
|
272
|
+
assert (sub01.to_numpy() == 1).all()
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
@pytest.mark.parametrize("klass", [HDF5FeatureStorage, SQLiteFeatureStorage])
|
|
276
|
+
def test_collect_several_elements(tmp_path: Path, klass: type) -> None:
|
|
277
|
+
"""Test collecting a file with more than one element raises an error.
|
|
278
|
+
|
|
279
|
+
Parameters
|
|
280
|
+
----------
|
|
281
|
+
tmp_path : pathlib.Path
|
|
282
|
+
The path to the test directory.
|
|
283
|
+
klass : type
|
|
284
|
+
The parametrized storage class.
|
|
285
|
+
|
|
286
|
+
"""
|
|
287
|
+
# A file with two elements, named as the file of an element
|
|
288
|
+
several = klass(uri=tmp_path / "element_all_out.db")
|
|
289
|
+
for subject in ("sub-01", "sub-02"):
|
|
290
|
+
_store(several, "timeseries", {"subject": subject}, 1)
|
|
291
|
+
storage = klass(uri=tmp_path / "out.db", single_output=False)
|
|
292
|
+
with pytest.raises(RuntimeError, match="has 2 elements for the feature"):
|
|
293
|
+
storage.collect()
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
# License: AGPL
|
|
6
6
|
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import Union
|
|
9
8
|
|
|
10
9
|
import numpy as np
|
|
11
10
|
import pandas as pd
|
|
@@ -14,7 +13,7 @@ from numpy.testing import assert_array_equal
|
|
|
14
13
|
from pandas.testing import assert_frame_equal
|
|
15
14
|
from sqlalchemy import create_engine
|
|
16
15
|
|
|
17
|
-
from junifer.storage
|
|
16
|
+
from junifer.storage import MatrixKind, SQLiteFeatureStorage, Upsert
|
|
18
17
|
from junifer.storage.utils import element_to_prefix, process_meta
|
|
19
18
|
|
|
20
19
|
|
|
@@ -56,7 +55,7 @@ df_ignore = pd.DataFrame(
|
|
|
56
55
|
|
|
57
56
|
|
|
58
57
|
def _read_sql(
|
|
59
|
-
table_name: str, uri: str, index_col:
|
|
58
|
+
table_name: str, uri: str, index_col: str | list[str]
|
|
60
59
|
) -> pd.DataFrame:
|
|
61
60
|
"""Read database table into a pandas DataFrame.
|
|
62
61
|
|
|
@@ -215,7 +214,7 @@ def test_upsert_update(tmp_path: Path) -> None:
|
|
|
215
214
|
|
|
216
215
|
"""
|
|
217
216
|
uri = tmp_path / "test_upsert_delete.sqlite"
|
|
218
|
-
storage = SQLiteFeatureStorage(uri=uri)
|
|
217
|
+
storage = SQLiteFeatureStorage(uri=uri, upsert=Upsert.Update)
|
|
219
218
|
# Save to database
|
|
220
219
|
storage.store_df(
|
|
221
220
|
meta_md5="table_name", element={"subject": "test"}, df=df1
|
|
@@ -503,16 +502,6 @@ def test_store_matrix(tmp_path: Path) -> None:
|
|
|
503
502
|
read_df = storage.read_df(feature_md5=feature_md5)
|
|
504
503
|
assert list(read_df.columns) == stored_names
|
|
505
504
|
|
|
506
|
-
with pytest.raises(ValueError, match="Invalid kind"):
|
|
507
|
-
storage.store_matrix(
|
|
508
|
-
meta_md5=meta_md5,
|
|
509
|
-
element=element_to_store,
|
|
510
|
-
data=data,
|
|
511
|
-
row_names=row_names,
|
|
512
|
-
col_names=col_names,
|
|
513
|
-
matrix_kind="wrong",
|
|
514
|
-
)
|
|
515
|
-
|
|
516
505
|
with pytest.raises(ValueError, match="non-square"):
|
|
517
506
|
storage.store_matrix(
|
|
518
507
|
meta_md5=meta_md5,
|
|
@@ -520,7 +509,7 @@ def test_store_matrix(tmp_path: Path) -> None:
|
|
|
520
509
|
data=data,
|
|
521
510
|
row_names=row_names,
|
|
522
511
|
col_names=col_names,
|
|
523
|
-
matrix_kind=
|
|
512
|
+
matrix_kind=MatrixKind.UpperTriangle,
|
|
524
513
|
)
|
|
525
514
|
|
|
526
515
|
with pytest.raises(ValueError, match="cannot be False"):
|
|
@@ -530,7 +519,7 @@ def test_store_matrix(tmp_path: Path) -> None:
|
|
|
530
519
|
data=data,
|
|
531
520
|
row_names=row_names,
|
|
532
521
|
col_names=col_names,
|
|
533
|
-
matrix_kind=
|
|
522
|
+
matrix_kind=MatrixKind.Full,
|
|
534
523
|
diagonal=False,
|
|
535
524
|
)
|
|
536
525
|
|
|
@@ -550,7 +539,7 @@ def test_store_matrix(tmp_path: Path) -> None:
|
|
|
550
539
|
data=data,
|
|
551
540
|
row_names=row_names,
|
|
552
541
|
col_names=col_names,
|
|
553
|
-
matrix_kind=
|
|
542
|
+
matrix_kind=MatrixKind.UpperTriangle,
|
|
554
543
|
)
|
|
555
544
|
|
|
556
545
|
stored_names = [
|
|
@@ -584,7 +573,7 @@ def test_store_matrix(tmp_path: Path) -> None:
|
|
|
584
573
|
data=data,
|
|
585
574
|
row_names=row_names,
|
|
586
575
|
col_names=col_names,
|
|
587
|
-
matrix_kind=
|
|
576
|
+
matrix_kind=MatrixKind.UpperTriangle,
|
|
588
577
|
diagonal=False,
|
|
589
578
|
)
|
|
590
579
|
|
|
@@ -619,7 +608,7 @@ def test_store_matrix(tmp_path: Path) -> None:
|
|
|
619
608
|
data=data,
|
|
620
609
|
row_names=row_names,
|
|
621
610
|
col_names=col_names,
|
|
622
|
-
matrix_kind=
|
|
611
|
+
matrix_kind=MatrixKind.LowerTriangle,
|
|
623
612
|
)
|
|
624
613
|
|
|
625
614
|
stored_names = [
|
|
@@ -653,7 +642,7 @@ def test_store_matrix(tmp_path: Path) -> None:
|
|
|
653
642
|
data=data,
|
|
654
643
|
row_names=row_names,
|
|
655
644
|
col_names=col_names,
|
|
656
|
-
matrix_kind=
|
|
645
|
+
matrix_kind=MatrixKind.LowerTriangle,
|
|
657
646
|
diagonal=False,
|
|
658
647
|
)
|
|
659
648
|
stored_names = [
|
|
@@ -5,17 +5,18 @@
|
|
|
5
5
|
# License: AGPL
|
|
6
6
|
|
|
7
7
|
from collections.abc import Sequence
|
|
8
|
+
from pathlib import Path
|
|
8
9
|
from typing import ClassVar
|
|
9
10
|
|
|
10
11
|
import pytest
|
|
11
12
|
|
|
12
|
-
from junifer.storage
|
|
13
|
+
from junifer.storage import BaseFeatureStorage, StorageType
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
def test_BaseFeatureStorage_abstractness() -> None:
|
|
16
17
|
"""Test BaseFeatureStorage is abstract base class."""
|
|
17
18
|
with pytest.raises(TypeError, match=r"abstract"):
|
|
18
|
-
BaseFeatureStorage(uri="
|
|
19
|
+
BaseFeatureStorage(uri=Path("."))
|
|
19
20
|
|
|
20
21
|
|
|
21
22
|
def test_BaseFeatureStorage() -> None:
|
|
@@ -25,19 +26,13 @@ def test_BaseFeatureStorage() -> None:
|
|
|
25
26
|
class MyFeatureStorage(BaseFeatureStorage):
|
|
26
27
|
"""Implement concrete class."""
|
|
27
28
|
|
|
28
|
-
_STORAGE_TYPES: ClassVar[Sequence[
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
_STORAGE_TYPES: ClassVar[Sequence[StorageType]] = [
|
|
30
|
+
StorageType.Matrix,
|
|
31
|
+
StorageType.Vector,
|
|
32
|
+
StorageType.Timeseries,
|
|
33
|
+
StorageType.Timeseries2D,
|
|
33
34
|
]
|
|
34
35
|
|
|
35
|
-
def __init__(self, uri, single_output=True):
|
|
36
|
-
super().__init__(
|
|
37
|
-
uri=uri,
|
|
38
|
-
single_output=single_output,
|
|
39
|
-
)
|
|
40
|
-
|
|
41
36
|
def list_features(self):
|
|
42
37
|
super().list_features()
|
|
43
38
|
|
|
@@ -53,24 +48,26 @@ def test_BaseFeatureStorage() -> None:
|
|
|
53
48
|
feature_md5=feature_md5,
|
|
54
49
|
)
|
|
55
50
|
|
|
56
|
-
def store_metadata(
|
|
57
|
-
|
|
51
|
+
def store_metadata(
|
|
52
|
+
self, meta_md5, element, meta, processed_element=None
|
|
53
|
+
):
|
|
54
|
+
super().store_metadata(meta_md5, meta, element, processed_element)
|
|
58
55
|
|
|
59
56
|
def collect(self):
|
|
60
|
-
|
|
57
|
+
super().collect()
|
|
61
58
|
|
|
62
59
|
# Check single_output is False
|
|
63
|
-
st = MyFeatureStorage(uri="
|
|
60
|
+
st = MyFeatureStorage(uri=Path("."), single_output=False)
|
|
64
61
|
assert st.single_output is False
|
|
65
62
|
# Check single_output is True
|
|
66
|
-
st = MyFeatureStorage(uri="
|
|
63
|
+
st = MyFeatureStorage(uri=Path("."), single_output=True)
|
|
67
64
|
assert st.single_output is True
|
|
68
65
|
|
|
69
66
|
# Check validate with valid argument
|
|
70
|
-
st.
|
|
67
|
+
st.validate_input(input_=["matrix"])
|
|
71
68
|
# Check validate with invalid argument
|
|
72
69
|
with pytest.raises(ValueError):
|
|
73
|
-
st.
|
|
70
|
+
st.validate_input(input_=["duck"])
|
|
74
71
|
|
|
75
72
|
with pytest.raises(NotImplementedError):
|
|
76
73
|
st.list_features()
|
|
@@ -109,4 +106,4 @@ def test_BaseFeatureStorage() -> None:
|
|
|
109
106
|
with pytest.raises(ValueError):
|
|
110
107
|
st.store(kind="lego", meta=meta)
|
|
111
108
|
|
|
112
|
-
assert str(st.uri) == "
|
|
109
|
+
assert str(st.uri) == "."
|
|
@@ -5,7 +5,6 @@
|
|
|
5
5
|
# License: AGPL
|
|
6
6
|
|
|
7
7
|
from collections.abc import Iterable
|
|
8
|
-
from typing import Union
|
|
9
8
|
|
|
10
9
|
import numpy as np
|
|
11
10
|
import pytest
|
|
@@ -24,14 +23,19 @@ from junifer.storage.utils import (
|
|
|
24
23
|
@pytest.mark.parametrize(
|
|
25
24
|
"dependency, max_version",
|
|
26
25
|
[
|
|
27
|
-
("click", "8.
|
|
28
|
-
("numpy", "
|
|
29
|
-
("
|
|
30
|
-
("
|
|
31
|
-
("
|
|
32
|
-
("
|
|
33
|
-
("
|
|
34
|
-
("
|
|
26
|
+
("click", "8.6"),
|
|
27
|
+
("numpy", "2.5.0"),
|
|
28
|
+
("scipy", "1.18.0"),
|
|
29
|
+
("datalad", "1.8.0"),
|
|
30
|
+
("pandas", "3.1.0"),
|
|
31
|
+
("nibabel", "5.5.0"),
|
|
32
|
+
("nilearn", "0.15.0"),
|
|
33
|
+
("sqlalchemy", "2.2.0"),
|
|
34
|
+
("ruamel.yaml", "0.20.0"),
|
|
35
|
+
("tqdm", "4.71.0"),
|
|
36
|
+
("templateflow", "26.0.0"),
|
|
37
|
+
("lapy", "2.0.0"),
|
|
38
|
+
("structlog", "27.0.0"),
|
|
35
39
|
],
|
|
36
40
|
)
|
|
37
41
|
def test_get_dependency_version(dependency: str, max_version: str) -> None:
|
|
@@ -47,7 +51,7 @@ def test_get_dependency_version(dependency: str, max_version: str) -> None:
|
|
|
47
51
|
"""
|
|
48
52
|
version = get_dependency_version(dependency)
|
|
49
53
|
if len(version.split(".")) == 3: # semver
|
|
50
|
-
assert int(version.split(".")[
|
|
54
|
+
assert int(version.split(".")[0]) <= int(max_version.split(".")[0])
|
|
51
55
|
else:
|
|
52
56
|
assert version < max_version
|
|
53
57
|
|
|
@@ -150,6 +154,73 @@ def test_process_meta_hash() -> None:
|
|
|
150
154
|
assert hash4 != hash6
|
|
151
155
|
|
|
152
156
|
|
|
157
|
+
def test_process_meta_element_keys() -> None:
|
|
158
|
+
"""Test metadata processing with the element keys of the data."""
|
|
159
|
+
meta = {
|
|
160
|
+
"element": {"subject": "sub-01", "task": "rest"},
|
|
161
|
+
"dependencies": ["numpy"],
|
|
162
|
+
"marker": {"name": "fc"},
|
|
163
|
+
"type": "VBM_GM",
|
|
164
|
+
}
|
|
165
|
+
# All the keys of the element by default
|
|
166
|
+
hash_all, meta_all, element_all = process_meta(meta)
|
|
167
|
+
assert element_all == {"subject": "sub-01", "task": "rest"}
|
|
168
|
+
assert meta_all["_element_keys"] == ["subject", "task"]
|
|
169
|
+
# Only the keys of the element that the data depends on, which are the
|
|
170
|
+
# same for all the tasks
|
|
171
|
+
hashes = set()
|
|
172
|
+
for task in ("rest", "movie"):
|
|
173
|
+
t_meta = {
|
|
174
|
+
**meta,
|
|
175
|
+
"element": {"subject": "sub-01", "task": task},
|
|
176
|
+
"_element_keys": ["subject"],
|
|
177
|
+
}
|
|
178
|
+
t_hash, t_processed, t_element = process_meta(t_meta)
|
|
179
|
+
assert t_element == {"subject": "sub-01"}
|
|
180
|
+
assert t_processed["_element_keys"] == ["subject"]
|
|
181
|
+
hashes.add(t_hash)
|
|
182
|
+
assert len(hashes) == 1
|
|
183
|
+
assert hash_all not in hashes
|
|
184
|
+
# Keys that are not in the element
|
|
185
|
+
with pytest.raises(ValueError, match=r"keys \['session'\]"):
|
|
186
|
+
process_meta({**meta, "_element_keys": ["subject", "session"]})
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def test_process_meta_preprocessors() -> None:
|
|
190
|
+
"""Test the metadata hash depends on all the preprocessors."""
|
|
191
|
+
hashes = []
|
|
192
|
+
for first in (1, 2):
|
|
193
|
+
meta = {
|
|
194
|
+
"element": {"subject": "sub-01"},
|
|
195
|
+
"dependencies": ["numpy"],
|
|
196
|
+
"preprocess": [
|
|
197
|
+
{"class": "A", "parameter": first},
|
|
198
|
+
{"class": "B", "parameter": 1},
|
|
199
|
+
],
|
|
200
|
+
"marker": {"name": "fc"},
|
|
201
|
+
"type": "BOLD",
|
|
202
|
+
}
|
|
203
|
+
t_hash, _, _ = process_meta(meta)
|
|
204
|
+
hashes.append(t_hash)
|
|
205
|
+
# Only the first preprocessor is different
|
|
206
|
+
assert hashes[0] != hashes[1]
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def test_process_meta_junifer_version() -> None:
|
|
210
|
+
"""Test the metadata hash depends on the version of junifer."""
|
|
211
|
+
meta = {
|
|
212
|
+
"element": {"subject": "sub-01"},
|
|
213
|
+
"dependencies": ["numpy"],
|
|
214
|
+
"marker": {"name": "fc"},
|
|
215
|
+
"type": "BOLD",
|
|
216
|
+
}
|
|
217
|
+
_, processed, _ = process_meta(meta)
|
|
218
|
+
assert processed["dependencies"] == {
|
|
219
|
+
"numpy": get_dependency_version("numpy"),
|
|
220
|
+
"junifer": get_dependency_version("junifer"),
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
|
|
153
224
|
def test_process_meta_invalid_metadata_key() -> None:
|
|
154
225
|
"""Test invalid metadata key check for metadata hash processing."""
|
|
155
226
|
meta = {}
|
|
@@ -259,16 +330,6 @@ def test_element_to_prefix_invalid_type() -> None:
|
|
|
259
330
|
@pytest.mark.parametrize(
|
|
260
331
|
"params, err_msg",
|
|
261
332
|
[
|
|
262
|
-
(
|
|
263
|
-
{
|
|
264
|
-
"matrix_kind": "half",
|
|
265
|
-
"diagonal": True,
|
|
266
|
-
"data_shape": (1, 1),
|
|
267
|
-
"row_names_len": 1,
|
|
268
|
-
"col_names_len": 1,
|
|
269
|
-
},
|
|
270
|
-
"Invalid kind",
|
|
271
|
-
),
|
|
272
333
|
(
|
|
273
334
|
{
|
|
274
335
|
"matrix_kind": "full",
|
|
@@ -322,7 +383,7 @@ def test_element_to_prefix_invalid_type() -> None:
|
|
|
322
383
|
],
|
|
323
384
|
)
|
|
324
385
|
def test_store_matrix_checks(
|
|
325
|
-
params: dict[str,
|
|
386
|
+
params: dict[str, str | bool | tuple[int, int] | int], err_msg: str
|
|
326
387
|
) -> None:
|
|
327
388
|
"""Test matrix storing parameter checks.
|
|
328
389
|
|
|
@@ -403,7 +464,7 @@ def test_store_matrix_checks(
|
|
|
403
464
|
],
|
|
404
465
|
)
|
|
405
466
|
def test_matrix_to_vector(
|
|
406
|
-
params: dict[str,
|
|
467
|
+
params: dict[str, np.ndarray | Iterable[str] | str | bool],
|
|
407
468
|
expected_data: np.ndarray,
|
|
408
469
|
expected_columns: list[str],
|
|
409
470
|
) -> None:
|