junifer 0.0.4.dev653__py3-none-any.whl → 0.0.4.dev691__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 CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.0.4.dev653'
16
- __version_tuple__ = version_tuple = (0, 0, 4, 'dev653')
15
+ __version__ = version = '0.0.4.dev691'
16
+ __version_tuple__ = version_tuple = (0, 0, 4, 'dev691')
@@ -274,8 +274,8 @@ class HTCondorAdapter(QueueContextAdapter):
274
274
  )
275
275
  fixed += (
276
276
  f"JOB run{idx} {self._submit_run_path}\n"
277
- f"VARS run{idx} element='{str_element}' "
278
- f"log_element='{log_element}'\n\n"
277
+ f'VARS run{idx} element="{str_element}" ' # needs to be
278
+ f'log_element="{log_element}"\n\n' # double quoted
279
279
  )
280
280
  var = ""
281
281
  if self._collect == "yes":
@@ -139,13 +139,13 @@ def test_HTCondorAdapter_run_collect(
139
139
  (
140
140
  [("sub01", "ses01")],
141
141
  "yes",
142
- "element='sub01,ses01' log_element='sub01-ses01'",
142
+ 'element="sub01,ses01" log_element="sub01-ses01"',
143
143
  ),
144
144
  (["sub01"], "on_success_only", "JOB collect"),
145
145
  (
146
146
  [("sub01", "ses01")],
147
147
  "on_success_only",
148
- "element='sub01,ses01' log_element='sub01-ses01'",
148
+ 'element="sub01,ses01" log_element="sub01-ses01"',
149
149
  ),
150
150
  ],
151
151
  )
@@ -45,9 +45,13 @@ def test_get_dependency_information_short() -> None:
45
45
  "httpx",
46
46
  "tqdm",
47
47
  "templateflow",
48
+ "looseversion",
48
49
  ]
49
- if int(pl.python_version_tuple()[1]) < 10:
50
+
51
+ python_minor_version = int(pl.python_version_tuple()[1])
52
+ if python_minor_version < 10:
50
53
  dependency_list.append("importlib_metadata")
54
+
51
55
  assert frozenset(dependency_information.keys()) == frozenset(
52
56
  dependency_list
53
57
  )
@@ -8,3 +8,4 @@
8
8
  from .base import BasePreprocessor
9
9
  from .confounds import fMRIPrepConfoundRemover
10
10
  from .bold_warper import BOLDWarper
11
+ from .warping import SpaceWarper
@@ -30,6 +30,10 @@ from .fsl.apply_warper import _ApplyWarper
30
30
  class BOLDWarper(BasePreprocessor):
31
31
  """Class for warping BOLD NIfTI images.
32
32
 
33
+ .. deprecated:: 0.0.3
34
+ `BOLDWarper` will be removed in v0.0.4, it is replaced by
35
+ `SpaceWarper` because the latter works also with T1w data.
36
+
33
37
  Parameters
34
38
  ----------
35
39
  using : {"fsl", "ants"}
@@ -0,0 +1,6 @@
1
+ """Provide imports for warping sub-package."""
2
+
3
+ # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
+ # License: AGPL
5
+
6
+ from .space_warper import SpaceWarper
@@ -0,0 +1,167 @@
1
+ """Provide class for space warping via ANTs antsApplyTransforms."""
2
+
3
+ # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
+ # License: AGPL
5
+
6
+ from typing import (
7
+ Any,
8
+ ClassVar,
9
+ Dict,
10
+ List,
11
+ Set,
12
+ Union,
13
+ )
14
+
15
+ import nibabel as nib
16
+ import numpy as np
17
+
18
+ from ...data import get_template, get_xfm
19
+ from ...pipeline import WorkDirManager
20
+ from ...utils import logger, run_ext_cmd
21
+
22
+
23
+ class ANTsWarper:
24
+ """Class for space warping via ANTs antsApplyTransforms.
25
+
26
+ This class uses ANTs' ``ResampleImage`` for resampling (if required) and
27
+ ``antsApplyTransforms`` for transformation.
28
+
29
+ """
30
+
31
+ _EXT_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, List[str]]]]] = [
32
+ {
33
+ "name": "ants",
34
+ "commands": ["ResampleImage", "antsApplyTransforms"],
35
+ },
36
+ ]
37
+
38
+ _DEPENDENCIES: ClassVar[Set[str]] = {"numpy", "nibabel"}
39
+
40
+ def preprocess(
41
+ self,
42
+ input: Dict[str, Any],
43
+ extra_input: Dict[str, Any],
44
+ reference: str,
45
+ ) -> Dict[str, Any]:
46
+ """Preprocess using ANTs.
47
+
48
+ Parameters
49
+ ----------
50
+ input : dict
51
+ A single input from the Junifer Data object in which to preprocess.
52
+ extra_input : dict
53
+ The other fields in the Junifer Data object. Should have ``T1w``
54
+ and ``Warp`` data types.
55
+ reference : str
56
+ The data type or template space to use as reference for warping.
57
+
58
+ Returns
59
+ -------
60
+ dict
61
+ The ``input`` dictionary with modified ``data`` and ``space`` key
62
+ values and new ``reference_path`` key whose value points to the
63
+ reference file used for warping.
64
+
65
+ """
66
+ # Create element-specific tempdir for storing post-warping assets
67
+ element_tempdir = WorkDirManager().get_element_tempdir(
68
+ prefix="ants_warper"
69
+ )
70
+
71
+ # Native space warping
72
+ if reference == "T1w":
73
+ logger.debug("Using ANTs for space warping")
74
+
75
+ # Get the min of the voxel sizes from input and use it as the
76
+ # resolution
77
+ resolution = np.min(input["data"].header.get_zooms()[:3])
78
+
79
+ # Create a tempfile for resampled reference output
80
+ resample_image_out_path = (
81
+ element_tempdir / "resampled_reference.nii.gz"
82
+ )
83
+ # Set ResampleImage command
84
+ resample_image_cmd = [
85
+ "ResampleImage",
86
+ "3", # image dimension
87
+ f"{extra_input['T1w']['path'].resolve()}",
88
+ f"{resample_image_out_path.resolve()}",
89
+ f"{resolution}x{resolution}x{resolution}",
90
+ "0", # option for spacing and not size
91
+ "3 3", # Lanczos windowed sinc
92
+ ]
93
+ # Call ResampleImage
94
+ run_ext_cmd(name="ResampleImage", cmd=resample_image_cmd)
95
+
96
+ # Create a tempfile for warped output
97
+ apply_transforms_out_path = element_tempdir / "output.nii.gz"
98
+ # Set antsApplyTransforms command
99
+ apply_transforms_cmd = [
100
+ "antsApplyTransforms",
101
+ "-d 3",
102
+ "-e 3",
103
+ "-n LanczosWindowedSinc",
104
+ f"-i {input['path'].resolve()}",
105
+ # use resampled reference
106
+ f"-r {resample_image_out_path.resolve()}",
107
+ f"-t {extra_input['Warp']['path'].resolve()}",
108
+ f"-o {apply_transforms_out_path.resolve()}",
109
+ ]
110
+ # Call antsApplyTransforms
111
+ run_ext_cmd(name="antsApplyTransforms", cmd=apply_transforms_cmd)
112
+
113
+ # Load nifti
114
+ input["data"] = nib.load(apply_transforms_out_path)
115
+ # Save resampled reference path
116
+ input["reference_path"] = resample_image_out_path
117
+ # Use reference input's space as warped input's space
118
+ input["space"] = extra_input["T1w"]["space"]
119
+
120
+ # Template space warping
121
+ else:
122
+ logger.debug(
123
+ f"Using ANTs to warp data from {input['space']} to {reference}"
124
+ )
125
+
126
+ # Get xfm file
127
+ xfm_file_path = get_xfm(src=input["space"], dst=reference)
128
+ # Get template space image
129
+ template_space_img = get_template(
130
+ space=reference,
131
+ target_data=input,
132
+ extra_input=None,
133
+ )
134
+
135
+ # Create component-scoped tempdir
136
+ tempdir = WorkDirManager().get_tempdir(prefix="ants_warper")
137
+ # Save template
138
+ template_space_img_path = tempdir / f"{reference}_T1w.nii.gz"
139
+ nib.save(template_space_img, template_space_img_path)
140
+
141
+ # Create a tempfile for warped output
142
+ warped_output_path = element_tempdir / (
143
+ f"data_warped_from_{input['space']}_to_" f"{reference}.nii.gz"
144
+ )
145
+
146
+ # Set antsApplyTransforms command
147
+ apply_transforms_cmd = [
148
+ "antsApplyTransforms",
149
+ "-d 3",
150
+ "-e 3",
151
+ "-n LanczosWindowedSinc",
152
+ f"-i {input['path'].resolve()}",
153
+ f"-r {template_space_img_path.resolve()}",
154
+ f"-t {xfm_file_path.resolve()}",
155
+ f"-o {warped_output_path.resolve()}",
156
+ ]
157
+ # Call antsApplyTransforms
158
+ run_ext_cmd(name="antsApplyTransforms", cmd=apply_transforms_cmd)
159
+
160
+ # Delete tempdir
161
+ WorkDirManager().delete_tempdir(tempdir)
162
+
163
+ # Modify target data
164
+ input["data"] = nib.load(warped_output_path)
165
+ input["space"] = reference
166
+
167
+ return input
@@ -0,0 +1,109 @@
1
+ """Provide class for space warping via FSL FLIRT."""
2
+
3
+ # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
+ # License: AGPL
5
+
6
+ from typing import (
7
+ Any,
8
+ ClassVar,
9
+ Dict,
10
+ List,
11
+ Set,
12
+ Union,
13
+ )
14
+
15
+ import nibabel as nib
16
+ import numpy as np
17
+
18
+ from ...pipeline import WorkDirManager
19
+ from ...utils import logger, run_ext_cmd
20
+
21
+
22
+ class FSLWarper:
23
+ """Class for space warping via FSL FLIRT.
24
+
25
+ This class uses FSL FLIRT's ``flirt`` for resampling and ``applywarp`` for
26
+ transformation.
27
+
28
+ """
29
+
30
+ _EXT_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, List[str]]]]] = [
31
+ {
32
+ "name": "fsl",
33
+ "commands": ["flirt", "applywarp"],
34
+ },
35
+ ]
36
+
37
+ _DEPENDENCIES: ClassVar[Set[str]] = {"numpy", "nibabel"}
38
+
39
+ def preprocess(
40
+ self,
41
+ input: Dict[str, Any],
42
+ extra_input: Dict[str, Any],
43
+ ) -> Dict[str, Any]:
44
+ """Preprocess using FSL.
45
+
46
+ Parameters
47
+ ----------
48
+ input : dict
49
+ A single input from the Junifer Data object in which to preprocess.
50
+ extra_input : dict
51
+ The other fields in the Junifer Data object. Should have ``T1w``
52
+ and ``Warp`` data types.
53
+
54
+ Returns
55
+ -------
56
+ dict
57
+ The ``input`` dictionary with modified ``data`` and ``space`` key
58
+ values and new ``reference_path`` key whose value points to the
59
+ reference file used for warping.
60
+
61
+ """
62
+ logger.debug("Using FSL for space warping")
63
+
64
+ # Get the min of the voxel sizes from input and use it as the
65
+ # resolution
66
+ resolution = np.min(input["data"].header.get_zooms()[:3])
67
+
68
+ # Create element-specific tempdir for storing post-warping assets
69
+ element_tempdir = WorkDirManager().get_element_tempdir(
70
+ prefix="fsl_warper"
71
+ )
72
+
73
+ # Create a tempfile for resampled reference output
74
+ flirt_out_path = element_tempdir / "resampled_reference.nii.gz"
75
+ # Set flirt command
76
+ flirt_cmd = [
77
+ "flirt",
78
+ "-interp spline",
79
+ f"-in {extra_input['T1w']['path'].resolve()}",
80
+ f"-ref {extra_input['T1w']['path'].resolve()}",
81
+ f"-applyisoxfm {resolution}",
82
+ f"-out {flirt_out_path.resolve()}",
83
+ ]
84
+ # Call flirt
85
+ run_ext_cmd(name="flirt", cmd=flirt_cmd)
86
+
87
+ # Create a tempfile for warped output
88
+ applywarp_out_path = element_tempdir / "output.nii.gz"
89
+ # Set applywarp command
90
+ applywarp_cmd = [
91
+ "applywarp",
92
+ "--interp=spline",
93
+ f"-i {input['path'].resolve()}",
94
+ f"-r {flirt_out_path.resolve()}", # use resampled reference
95
+ f"-w {extra_input['Warp']['path'].resolve()}",
96
+ f"-o {applywarp_out_path.resolve()}",
97
+ ]
98
+ # Call applywarp
99
+ run_ext_cmd(name="applywarp", cmd=applywarp_cmd)
100
+
101
+ # Load nifti
102
+ input["data"] = nib.load(applywarp_out_path)
103
+ # Save resampled reference path
104
+ input["reference_path"] = flirt_out_path
105
+
106
+ # Use reference input's space as warped input's space
107
+ input["space"] = extra_input["T1w"]["space"]
108
+
109
+ return input
@@ -0,0 +1,203 @@
1
+ """Provide class for warping data to other template spaces."""
2
+
3
+ # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
+ # License: AGPL
5
+
6
+ from typing import Any, ClassVar, Dict, List, Optional, Tuple, Type, Union
7
+
8
+ from templateflow import api as tflow
9
+
10
+ from ...api.decorators import register_preprocessor
11
+ from ...utils import logger, raise_error
12
+ from ..base import BasePreprocessor
13
+ from ._ants_warper import ANTsWarper
14
+ from ._fsl_warper import FSLWarper
15
+
16
+
17
+ __all__ = ["SpaceWarper"]
18
+
19
+
20
+ @register_preprocessor
21
+ class SpaceWarper(BasePreprocessor):
22
+ """Class for warping data to other template spaces.
23
+
24
+ Parameters
25
+ ----------
26
+ using : {"fsl", "ants"}
27
+ Implementation to use for warping:
28
+
29
+ * "fsl" : Use FSL's ``applywarp``
30
+ * "ants" : Use ANTs' ``antsApplyTransforms``
31
+
32
+ reference : str
33
+ The data type to use as reference for warping, can be either a data
34
+ type like ``"T1w"`` or a template space like ``"MNI152NLin2009cAsym"``.
35
+ Use ``"T1w"`` for native space warping and named templates for
36
+ template space warping.
37
+ on : {"T1w", "BOLD", "VBM_GM", "VBM_WM", "fALFF", "GCOR", "LCOR"} or list \
38
+ of the options
39
+ The data type to warp.
40
+
41
+ Raises
42
+ ------
43
+ ValueError
44
+ If ``using`` is invalid or
45
+ if ``reference`` is invalid.
46
+
47
+ """
48
+
49
+ _CONDITIONAL_DEPENDENCIES: ClassVar[List[Dict[str, Union[str, Type]]]] = [
50
+ {
51
+ "using": "fsl",
52
+ "depends_on": FSLWarper,
53
+ },
54
+ {
55
+ "using": "ants",
56
+ "depends_on": ANTsWarper,
57
+ },
58
+ ]
59
+
60
+ def __init__(
61
+ self, using: str, reference: str, on: Union[List[str], str]
62
+ ) -> None:
63
+ """Initialize the class."""
64
+ # Validate `using` parameter
65
+ valid_using = [dep["using"] for dep in self._CONDITIONAL_DEPENDENCIES]
66
+ if using not in valid_using:
67
+ raise_error(
68
+ f"Invalid value for `using`, should be one of: {valid_using}"
69
+ )
70
+ self.using = using
71
+ self.reference = reference
72
+ # Set required data types based on reference and
73
+ # initialize superclass
74
+ if self.reference == "T1w":
75
+ required_data_types = [self.reference, "Warp"]
76
+ # Listify on
77
+ if not isinstance(on, list):
78
+ on = [on]
79
+ # Extend required data types
80
+ required_data_types.extend(on)
81
+
82
+ super().__init__(
83
+ on=on,
84
+ required_data_types=required_data_types,
85
+ )
86
+ elif self.reference in tflow.templates():
87
+ super().__init__(on=on)
88
+ else:
89
+ raise_error(f"Unknown reference: {self.reference}")
90
+
91
+ def get_valid_inputs(self) -> List[str]:
92
+ """Get valid data types for input.
93
+
94
+ Returns
95
+ -------
96
+ list of str
97
+ The list of data types that can be used as input for this
98
+ preprocessor.
99
+
100
+ """
101
+ return ["T1w", "BOLD", "VBM_GM", "VBM_WM", "fALFF", "GCOR", "LCOR"]
102
+
103
+ def get_output_type(self, input_type: str) -> str:
104
+ """Get output type.
105
+
106
+ Parameters
107
+ ----------
108
+ input_type : str
109
+ The data type input to the preprocessor.
110
+
111
+ Returns
112
+ -------
113
+ str
114
+ The data type output by the preprocessor.
115
+
116
+ """
117
+ # Does not add any new keys
118
+ return input_type
119
+
120
+ def preprocess(
121
+ self,
122
+ input: Dict[str, Any],
123
+ extra_input: Optional[Dict[str, Any]] = None,
124
+ ) -> Tuple[Dict[str, Any], Optional[Dict[str, Dict[str, Any]]]]:
125
+ """Preprocess.
126
+
127
+ Parameters
128
+ ----------
129
+ input : dict
130
+ The input from the Junifer Data object.
131
+ extra_input : dict, optional
132
+ The other fields in the Junifer Data object.
133
+
134
+ Returns
135
+ -------
136
+ dict
137
+ The computed result as dictionary.
138
+ None
139
+ Extra "helper" data types as dictionary to add to the Junifer Data
140
+ object.
141
+
142
+ Raises
143
+ ------
144
+ ValueError
145
+ If ``extra_input`` is None when transforming to native space
146
+ i.e., using ``"T1w"`` as reference.
147
+ RuntimeError
148
+ If the data is in the correct space and does not require
149
+ warping or
150
+ if FSL is used for template space warping.
151
+
152
+ """
153
+ logger.info(f"Warping to {self.reference} space using SpaceWarper")
154
+ # Transform to native space
155
+ if self.using in ["fsl", "ants"] and self.reference == "T1w":
156
+ # Check for extra inputs
157
+ if extra_input is None:
158
+ raise_error(
159
+ "No extra input provided, requires `Warp` and "
160
+ f"`{self.reference}` data types in particular."
161
+ )
162
+ # Conditional preprocessor
163
+ if self.using == "fsl":
164
+ input = FSLWarper().preprocess(
165
+ input=input,
166
+ extra_input=extra_input,
167
+ )
168
+ elif self.using == "ants":
169
+ input = ANTsWarper().preprocess(
170
+ input=input,
171
+ extra_input=extra_input,
172
+ reference=self.reference,
173
+ )
174
+ # Transform to template space with ANTs possible
175
+ elif self.using == "ants" and self.reference != "T1w":
176
+ # Check pre-requirements for space manipulation
177
+ if self.reference == input["space"]:
178
+ raise_error(
179
+ (
180
+ f"The target data is in {self.reference} space "
181
+ "and thus warping will not be performed, hence you "
182
+ "should remove the SpaceWarper from the preprocess "
183
+ "step."
184
+ ),
185
+ klass=RuntimeError,
186
+ )
187
+
188
+ input = ANTsWarper().preprocess(
189
+ input=input,
190
+ extra_input={},
191
+ reference=self.reference,
192
+ )
193
+ # Transform to template space with FSL not possible
194
+ elif self.using == "fsl" and self.reference != "T1w":
195
+ raise_error(
196
+ (
197
+ f"Warping to {self.reference} space not possible with "
198
+ "FSL, use ANTs instead."
199
+ ),
200
+ klass=RuntimeError,
201
+ )
202
+
203
+ return input, None
@@ -0,0 +1,198 @@
1
+ """Provide tests for SpaceWarper."""
2
+
3
+ # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
+ # License: AGPL
5
+
6
+ import socket
7
+ from typing import TYPE_CHECKING, Tuple, Type
8
+
9
+ import pytest
10
+ from numpy.testing import assert_array_equal, assert_raises
11
+
12
+ from junifer.datagrabber import DataladHCP1200, DMCC13Benchmark
13
+ from junifer.datareader import DefaultDataReader
14
+ from junifer.pipeline.utils import _check_ants, _check_fsl
15
+ from junifer.preprocess import SpaceWarper
16
+ from junifer.testing.datagrabbers import PartlyCloudyTestingDataGrabber
17
+
18
+
19
+ if TYPE_CHECKING:
20
+ from junifer.datagrabber import BaseDataGrabber
21
+
22
+
23
+ @pytest.mark.parametrize(
24
+ "using, reference, error_type, error_msg",
25
+ [
26
+ ("jam", "T1w", ValueError, "`using`"),
27
+ ("ants", "juice", ValueError, "reference"),
28
+ ("ants", "MNI152NLin2009cAsym", RuntimeError, "remove"),
29
+ ("fsl", "MNI152NLin2009cAsym", RuntimeError, "ANTs"),
30
+ ],
31
+ )
32
+ def test_SpaceWarper_errors(
33
+ using: str,
34
+ reference: str,
35
+ error_type: Type[Exception],
36
+ error_msg: str,
37
+ ) -> None:
38
+ """Test SpaceWarper errors.
39
+
40
+ Parameters
41
+ ----------
42
+ using : str
43
+ The parametrized implementation method.
44
+ reference : str
45
+ The parametrized reference to use.
46
+ error_type : Exception-like object
47
+ The parametrized exception to check.
48
+ error_msg : str
49
+ The parametrized exception message to check.
50
+
51
+ """
52
+ with PartlyCloudyTestingDataGrabber() as dg:
53
+ # Read data
54
+ element_data = DefaultDataReader().fit_transform(dg["sub-01"])
55
+ # Preprocess data
56
+ with pytest.raises(error_type, match=error_msg):
57
+ SpaceWarper(
58
+ using=using,
59
+ reference=reference,
60
+ on="BOLD",
61
+ ).preprocess(
62
+ input=element_data["BOLD"],
63
+ extra_input=element_data,
64
+ )
65
+
66
+
67
+ @pytest.mark.parametrize(
68
+ "datagrabber, element, using",
69
+ [
70
+ [
71
+ DMCC13Benchmark(
72
+ types=["BOLD", "T1w", "Warp"],
73
+ sessions=["wave1bas"],
74
+ tasks=["Rest"],
75
+ phase_encodings=["AP"],
76
+ runs=["1"],
77
+ native_t1w=True,
78
+ ),
79
+ ("f9057kp", "wave1bas", "Rest", "AP", "1"),
80
+ "ants",
81
+ ],
82
+ [
83
+ DataladHCP1200(
84
+ tasks=["REST1"],
85
+ phase_encodings=["LR"],
86
+ ica_fix=True,
87
+ ),
88
+ ("100206", "REST1", "LR"),
89
+ "fsl",
90
+ ],
91
+ ],
92
+ )
93
+ @pytest.mark.skipif(_check_fsl() is False, reason="requires FSL to be in PATH")
94
+ @pytest.mark.skipif(
95
+ _check_ants() is False, reason="requires ANTs to be in PATH"
96
+ )
97
+ @pytest.mark.skipif(
98
+ socket.gethostname() != "juseless",
99
+ reason="only for juseless",
100
+ )
101
+ def test_SpaceWarper_native(
102
+ datagrabber: "BaseDataGrabber", element: Tuple[str, ...], using: str
103
+ ) -> None:
104
+ """Test SpaceWarper for native space warping.
105
+
106
+ Parameters
107
+ ----------
108
+ datagrabber : DataGrabber-like object
109
+ The parametrized DataGrabber objects.
110
+ element : tuple of str
111
+ The parametrized elements.
112
+ using : str
113
+ The parametrized implementation method.
114
+
115
+ """
116
+ with datagrabber as dg:
117
+ # Read data
118
+ element_data = DefaultDataReader().fit_transform(dg[element])
119
+ # Preprocess data
120
+ output, _ = SpaceWarper(
121
+ using=using,
122
+ reference="T1w",
123
+ on="BOLD",
124
+ ).preprocess(
125
+ input=element_data["BOLD"],
126
+ extra_input=element_data,
127
+ )
128
+ # Check
129
+ assert isinstance(output, dict)
130
+
131
+
132
+ @pytest.mark.parametrize(
133
+ "datagrabber, element, space",
134
+ [
135
+ [
136
+ DMCC13Benchmark(
137
+ types=["T1w"],
138
+ sessions=["wave1bas"],
139
+ tasks=["Rest"],
140
+ phase_encodings=["AP"],
141
+ runs=["1"],
142
+ native_t1w=False,
143
+ ),
144
+ ("f9057kp", "wave1bas", "Rest", "AP", "1"),
145
+ "MNI152NLin2009aAsym",
146
+ ],
147
+ [
148
+ DMCC13Benchmark(
149
+ types=["T1w"],
150
+ sessions=["wave1bas"],
151
+ tasks=["Rest"],
152
+ phase_encodings=["AP"],
153
+ runs=["1"],
154
+ native_t1w=False,
155
+ ),
156
+ ("f9057kp", "wave1bas", "Rest", "AP", "1"),
157
+ "MNI152NLin6Asym",
158
+ ],
159
+ ],
160
+ )
161
+ @pytest.mark.skipif(
162
+ _check_ants() is False, reason="requires ANTs to be in PATH"
163
+ )
164
+ def test_SpaceWarper_multi_mni(
165
+ datagrabber: "BaseDataGrabber",
166
+ element: Tuple[str, ...],
167
+ space: str,
168
+ ) -> None:
169
+ """Test SpaceWarper for MNI space warping.
170
+
171
+ Parameters
172
+ ----------
173
+ datagrabber : DataGrabber-like object
174
+ The parametrized DataGrabber objects.
175
+ element : tuple of str
176
+ The parametrized elements.
177
+ space : str
178
+ The parametrized template space to transform to.
179
+
180
+ """
181
+ with datagrabber as dg:
182
+ # Read data
183
+ element_data = DefaultDataReader().fit_transform(dg[element])
184
+ pre_xfm_data = element_data["T1w"]["data"].get_fdata().copy()
185
+ # Preprocess data
186
+ output, _ = SpaceWarper(
187
+ using="ants",
188
+ reference=space,
189
+ on=["T1w"],
190
+ ).preprocess(
191
+ input=element_data["T1w"],
192
+ extra_input=element_data,
193
+ )
194
+ # Checks
195
+ assert isinstance(output, dict)
196
+ assert output["space"] == space
197
+ with assert_raises(AssertionError):
198
+ assert_array_equal(pre_xfm_data, output["data"])
junifer/utils/logging.py CHANGED
@@ -4,9 +4,13 @@
4
4
  # Synchon Mandal <s.mandal@fz-juelich.de>
5
5
  # License: AGPL
6
6
 
7
+ try:
8
+ from distutils.version import LooseVersion
9
+ except ImportError: # pragma: no cover
10
+ from looseversion import LooseVersion
11
+
7
12
  import logging
8
13
  import sys
9
- from distutils.version import LooseVersion
10
14
  from pathlib import Path
11
15
  from subprocess import PIPE, Popen, TimeoutExpired
12
16
  from typing import Dict, NoReturn, Optional, Type, Union
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: junifer
3
- Version: 0.0.4.dev653
3
+ Version: 0.0.4.dev691
4
4
  Summary: JUelich NeuroImaging FEature extractoR
5
5
  Author-email: Fede Raimondo <f.raimondo@fz-juelich.de>, Synchon Mandal <s.mandal@fz-juelich.de>
6
6
  Maintainer-email: Fede Raimondo <f.raimondo@fz-juelich.de>, Synchon Mandal <s.mandal@fz-juelich.de>
@@ -23,6 +23,7 @@ Classifier: Programming Language :: Python :: 3.8
23
23
  Classifier: Programming Language :: Python :: 3.9
24
24
  Classifier: Programming Language :: Python :: 3.10
25
25
  Classifier: Programming Language :: Python :: 3.11
26
+ Classifier: Programming Language :: Python :: 3.12
26
27
  Requires-Python: >=3.8
27
28
  Description-Content-Type: text/markdown
28
29
  License-File: LICENSE.md
@@ -36,11 +37,12 @@ Requires-Dist: nibabel <5.11,>=3.2.0
36
37
  Requires-Dist: nilearn <=0.10.2,>=0.9.0
37
38
  Requires-Dist: sqlalchemy <=2.1.0,>=1.4.27
38
39
  Requires-Dist: ruamel.yaml <0.18,>=0.17
39
- Requires-Dist: h5py <3.10,>=3.8.0
40
+ Requires-Dist: h5py >=3.10
40
41
  Requires-Dist: httpx[http2] ==0.26.0
41
42
  Requires-Dist: tqdm ==4.66.1
42
43
  Requires-Dist: templateflow >=23.0.0
43
44
  Requires-Dist: importlib-metadata ; python_version < "3.10"
45
+ Requires-Dist: looseversion ==1.3.0 ; python_version >= "3.12"
44
46
  Provides-Extra: all
45
47
  Requires-Dist: bctpy ==0.6.0 ; extra == 'all'
46
48
  Requires-Dist: neurokit2 >=0.1.7 ; extra == 'all'
@@ -1,5 +1,5 @@
1
1
  junifer/__init__.py,sha256=x1UR2jUcrUdm2HNl-3Qvyi4UUrU6ms5qm2qcmNY7zZk,391
2
- junifer/_version.py,sha256=gBf3eNHyfTa8ST1xQLRioVh0Jn44BrNC56F0nXzAvt8,428
2
+ junifer/_version.py,sha256=2WPaxhKlhwhDOGRx-9LuqipNV4sZTUszLPQ6IRWVxY0,428
3
3
  junifer/stats.py,sha256=sU5IZ2qFZWbzgSutQS_z42miIVItpSGmQYBn6KkD5fA,6162
4
4
  junifer/api/__init__.py,sha256=YILu9M7SC0Ri4CVd90fELH2OnK_gvCYAXCoqBNCFE8E,257
5
5
  junifer/api/cli.py,sha256=auw38tIH7ipTnaADM7on0or7zauY-BFII8nd-eRUEJs,13664
@@ -8,9 +8,9 @@ junifer/api/functions.py,sha256=Nvkby-Nlef_mMizdENC_Bodx8_MS5yoJ0nLsU7aGMgE,1125
8
8
  junifer/api/parser.py,sha256=a3SSC2xO-PF1pqXZXFq8Sh9aVd-dmHolJbCkGyOUTAM,4416
9
9
  junifer/api/utils.py,sha256=dyjTdPMwX9qeCrn8SQT2Pjshfnu-y1FEyujV7lCzvm0,3333
10
10
  junifer/api/queue_context/__init__.py,sha256=lrDX54HCWt7-hvJ2XTP3dADQhWFFZZR9GfZh2cgCyAI,223
11
- junifer/api/queue_context/htcondor_adapter.py,sha256=KtIybl7OXueogvmVvcETflhPcCgI3QMi0ufFMv8PBEc,12649
11
+ junifer/api/queue_context/htcondor_adapter.py,sha256=XEzwMCFwGCoSReJKm3TU9poVN5-7lRZ1KUJw6_8v0b0,12681
12
12
  junifer/api/queue_context/queue_context_adapter.py,sha256=a6UE8xavDfuaZbkWYsayVs6l-rwIrbpFSpqSyHsEeYY,1577
13
- junifer/api/queue_context/tests/test_htcondor_adapter.py,sha256=SwcBEpWYtu6KVMG1aLubrfGlQVshqJfAltDsZtPXGho,7255
13
+ junifer/api/queue_context/tests/test_htcondor_adapter.py,sha256=XmtdqoUmYTdkwGqRvIX52_n-vaVnPfvz81K4iSc6P0c,7255
14
14
  junifer/api/res/run_conda.sh,sha256=eskIn-fotITOlh--IUQKXh-SBOZkDkK8QvDcdQsyJ0M,509
15
15
  junifer/api/res/run_venv.sh,sha256=OF-LOdOdpjCU0JX6Dz1boG4ErPutTiVVD_N7j520Fvk,499
16
16
  junifer/api/res/afni/3dAFNItoNIFTI,sha256=Fsy5S5rwIBb1MepLfl_5FQhE7gv6NDwNyAR_k036NmM,51
@@ -27,7 +27,7 @@ junifer/api/res/fsl/flirt,sha256=tSjiUco8ui8AbHD7mTzChEwbR0Rf_4iJTgzYTPF_WuQ,42
27
27
  junifer/api/res/fsl/img2imgcoord,sha256=Zmaw3oJYrEltcXiPyEubXry9ppAq3SND52tdDWGgeZk,49
28
28
  junifer/api/res/fsl/run_fsl_docker.sh,sha256=mRLtZo0OgDwleoee2MG6rYI37HVuGNk9zOADwcl97RA,1122
29
29
  junifer/api/res/fsl/std2imgcoord,sha256=-X5wRH6XMl0yqnTACJX6MFhO8DFOEWg42MHRxGvimXg,49
30
- junifer/api/tests/test_api_utils.py,sha256=OG7xZyncYAfAIzrnC_4gtpVgpyfIwpr3LjtPqSM1F54,2639
30
+ junifer/api/tests/test_api_utils.py,sha256=zDRQiqFOaoO02FpzJCxEbZvsP4u4__Yr25e5k5MJwuI,2713
31
31
  junifer/api/tests/test_cli.py,sha256=hou8Jn31v0SfjAwf5zIqQEbA1nxvL6uvVZUjnghAG3k,8553
32
32
  junifer/api/tests/test_functions.py,sha256=WvedMpHZ9ckbvkuOgCxnyZLrKdi5bR4hGJyO6ywkbIA,15531
33
33
  junifer/api/tests/test_parser.py,sha256=eUz2JPVb0_cxvoeI1O_C5PMNs5v_lDzGsN6fV1VW5Eg,6109
@@ -197,9 +197,9 @@ junifer/pipeline/tests/test_pipeline_step_mixin.py,sha256=_ykZzyNzREXy-r_yv1gY_j
197
197
  junifer/pipeline/tests/test_registry.py,sha256=rYN0pO3gSueQ6XsasEM9VU5BkLyaNl8WaCZiaO8Rno0,4105
198
198
  junifer/pipeline/tests/test_update_meta_mixin.py,sha256=UeWwpUi-Q5WVd36Fgfn_utXplSVXMSjLcdO2mR2xLTk,1355
199
199
  junifer/pipeline/tests/test_workdir_manager.py,sha256=E1WY4C-GDsx2c49sePqr1WR_Y3nZ1kiRn4Veu506uTs,2801
200
- junifer/preprocess/__init__.py,sha256=-3exohZnw-gJ-MjVM63WcXzBW1mbSetEVozcDfs5etc,342
200
+ junifer/preprocess/__init__.py,sha256=fPZPFvx-BIUswBP4bx5HdBG1vLFkUMI4mnn6li339wU,375
201
201
  junifer/preprocess/base.py,sha256=Bn1VdonQ1f_DDPwFMpdaeyfLfNSnROulr-U8HuGQ81A,6697
202
- junifer/preprocess/bold_warper.py,sha256=fzZeJLZ21y0ZzgLnPbjGBaRnt5ljtzSTQF6qZj4qR9g,8888
202
+ junifer/preprocess/bold_warper.py,sha256=pEQ1GaWTV2Ili9WyqJgtq0PGHm4hNztXyY9ixoLNZnw,9060
203
203
  junifer/preprocess/ants/__init__.py,sha256=Uobmbhh6_gOowkF2hQNSQOh3AYeaXzarBXEcLJzhERE,112
204
204
  junifer/preprocess/ants/ants_apply_transforms_warper.py,sha256=1qkTq4NoW-c8CDEvh8j4uuN_HtneXSpG0mqRc6_qrNk,5556
205
205
  junifer/preprocess/ants/tests/test_ants_apply_transforms_warper.py,sha256=jJMZvX_3VDpXaxLDRNtVzlqcRsHjDTsUa_VywJ8rniE,1666
@@ -211,6 +211,11 @@ junifer/preprocess/fsl/apply_warper.py,sha256=k6ZzoDhXgsqcJZYYdx45Y3rN9xJERc0295
211
211
  junifer/preprocess/fsl/tests/test_apply_warper.py,sha256=eCrSPYIGTKFDiBtseZFkghjhU7j7np59TZeGdKHkhMs,1324
212
212
  junifer/preprocess/tests/test_bold_warper.py,sha256=sPS8Xd9Ix5TIvxiTCkfRDcA_zxk-2UUteIt68Rv6JGw,4600
213
213
  junifer/preprocess/tests/test_preprocess_base.py,sha256=-0rpe8QjqYES36H6MHuDs3cv_6upHBdVHnFMgQsmEX4,2571
214
+ junifer/preprocess/warping/__init__.py,sha256=zW4DVt_RPJWT0-AsylGmh9wgFBDPkU-hx4VzV_qPayU,154
215
+ junifer/preprocess/warping/_ants_warper.py,sha256=Y1UzZ5jy1TvlLEkaQKW7jCNvEHufZMdQFbg2JpY3UaM,5690
216
+ junifer/preprocess/warping/_fsl_warper.py,sha256=eELmS44LYYANQaWR3VDKv8iwpEC2qnF9kbTYRanR2mE,3204
217
+ junifer/preprocess/warping/space_warper.py,sha256=honyMD9e2kK72oBWb4loA6lKZFs5kIjr1AYB4HU3eDQ,6435
218
+ junifer/preprocess/warping/tests/test_space_warper.py,sha256=ph92dIDOr9ih9tkqT0yo5tnQL3UkOgQRXG3WzP5QLSE,5586
214
219
  junifer/storage/__init__.py,sha256=QlzBw9UrRhmg_f7zQVas9h313u3sfZIBicA3_0Skm4M,337
215
220
  junifer/storage/base.py,sha256=UxDvj81gSmqqHspbSs1X_i9HvW5wXysDippI7HWM7aM,9654
216
221
  junifer/storage/hdf5.py,sha256=oxdPuCG0hxzSDNH0uHnYFwVr_wp0g9yvgZf8bv3PkJM,35631
@@ -236,14 +241,14 @@ junifer/tests/test_stats.py,sha256=3vPMgYYpWxk8ECDFOMm3-dFBlh4XxjL83SwRBSBAHok,4
236
241
  junifer/utils/__init__.py,sha256=sFpsDKbPPtoU3Db3OSO9Vo45u4yE7UfocNaBtD-qvdk,310
237
242
  junifer/utils/fs.py,sha256=Jd9AoV2fIF7pT7KhXsn8T1O1fJ1_SFZgaFuOBAM7DG8,460
238
243
  junifer/utils/helpers.py,sha256=Hp3yGZa9x659BCqFTd4keEU1gbHXNAbJ1_lHG1M6lwI,1338
239
- junifer/utils/logging.py,sha256=T0HgiCI6cS2tp9nbI4cM3nVzMMjiVzgoxuyo5Y1rCyY,9124
244
+ junifer/utils/logging.py,sha256=furcU3XIUpUvnpe4PEwzWWIWgmH4j2ZA4MQdvSGWjj0,9216
240
245
  junifer/utils/tests/test_fs.py,sha256=WQS7cKlKEZ742CIuiOYYpueeAhY9PqlastfDVpVVtvE,923
241
246
  junifer/utils/tests/test_helpers.py,sha256=k5qqfxK8dFyuewTJyR1Qn6-nFaYNuVr0ysc18bfPjyU,929
242
247
  junifer/utils/tests/test_logging.py,sha256=l8oo-AiBV7H6_IzlsNcj__cLeZBUvgIGoaMszD9VaJg,7754
243
- junifer-0.0.4.dev653.dist-info/AUTHORS.rst,sha256=rmULKpchpSol4ExWFdm-qu4fkpSZPYqIESVJBZtGb6E,163
244
- junifer-0.0.4.dev653.dist-info/LICENSE.md,sha256=MqCnOBu8uXsEOzRZWh9EBVfVz-kE9NkXcLCrtGXo2yU,34354
245
- junifer-0.0.4.dev653.dist-info/METADATA,sha256=TcibG_gBOkLM-aSZ2TQ_zj8ZTyHMTvG3MegsKZ7NSsU,8128
246
- junifer-0.0.4.dev653.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
247
- junifer-0.0.4.dev653.dist-info/entry_points.txt,sha256=DxFvKq0pOqRunAK0FxwJcoDfV1-dZvsFDpD5HRqSDhw,48
248
- junifer-0.0.4.dev653.dist-info/top_level.txt,sha256=4bAq1R2QFQ4b3hohjys2JBvxrl0GKk5LNFzYvz9VGcA,8
249
- junifer-0.0.4.dev653.dist-info/RECORD,,
248
+ junifer-0.0.4.dev691.dist-info/AUTHORS.rst,sha256=rmULKpchpSol4ExWFdm-qu4fkpSZPYqIESVJBZtGb6E,163
249
+ junifer-0.0.4.dev691.dist-info/LICENSE.md,sha256=MqCnOBu8uXsEOzRZWh9EBVfVz-kE9NkXcLCrtGXo2yU,34354
250
+ junifer-0.0.4.dev691.dist-info/METADATA,sha256=7usklSXm5dzCWLbRWRjXlHGaFEMdDuUjstrEtyOxwj8,8235
251
+ junifer-0.0.4.dev691.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
252
+ junifer-0.0.4.dev691.dist-info/entry_points.txt,sha256=DxFvKq0pOqRunAK0FxwJcoDfV1-dZvsFDpD5HRqSDhw,48
253
+ junifer-0.0.4.dev691.dist-info/top_level.txt,sha256=4bAq1R2QFQ4b3hohjys2JBvxrl0GKk5LNFzYvz9VGcA,8
254
+ junifer-0.0.4.dev691.dist-info/RECORD,,