junifer 0.0.4.dev517__py3-none-any.whl → 0.0.4.dev530__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.dev517'
16
- __version_tuple__ = version_tuple = (0, 0, 4, 'dev517')
15
+ __version__ = version = '0.0.4.dev530'
16
+ __version_tuple__ = version_tuple = (0, 0, 4, 'dev530')
@@ -4,7 +4,6 @@
4
4
  # Synchon Mandal <s.mandal@fz-juelich.de>
5
5
  # License: AGPL
6
6
 
7
- import subprocess
8
7
  import typing
9
8
  from pathlib import Path
10
9
  from typing import Any, Dict, List, Optional, Tuple, Union
@@ -14,7 +13,7 @@ import pandas as pd
14
13
  from numpy.typing import ArrayLike
15
14
 
16
15
  from ..pipeline import WorkDirManager
17
- from ..utils.logging import logger, raise_error, warn_with_log
16
+ from ..utils import logger, raise_error, run_ext_cmd, warn_with_log
18
17
 
19
18
 
20
19
  # Path to the VOIs
@@ -231,6 +230,8 @@ def get_coordinates(
231
230
 
232
231
  Raises
233
232
  ------
233
+ RuntimeError
234
+ If warp / transformation file extension is not ".mat" or ".h5".
234
235
  ValueError
235
236
  If ``extra_input`` is None when ``target_data``'s space is native.
236
237
 
@@ -286,30 +287,7 @@ def get_coordinates(
286
287
  f"sed -i 1d {transformed_coords_path.resolve()}",
287
288
  ]
288
289
  # Call img2imgcoord
289
- img2imgcoord_cmd_str = " ".join(img2imgcoord_cmd)
290
- logger.info(
291
- f"img2imgcoord command to be executed: {img2imgcoord_cmd_str}"
292
- )
293
- img2imgcoord_process = subprocess.run(
294
- img2imgcoord_cmd_str, # string needed with shell=True
295
- stdin=subprocess.DEVNULL,
296
- stdout=subprocess.PIPE,
297
- stderr=subprocess.STDOUT,
298
- shell=True, # needed for respecting $PATH
299
- check=False,
300
- )
301
- # Check for success or failure
302
- if img2imgcoord_process.returncode == 0:
303
- logger.info(
304
- "img2imgcoord succeeded with the following output: "
305
- f"{img2imgcoord_process.stdout}"
306
- )
307
- else:
308
- raise_error(
309
- msg="img2imgcoord failed with the following error: "
310
- f"{img2imgcoord_process.stdout}",
311
- klass=RuntimeError,
312
- )
290
+ run_ext_cmd(name="img2imgcoord", cmd=img2imgcoord_cmd)
313
291
 
314
292
  # Load coordinates
315
293
  seeds = np.loadtxt(transformed_coords_path)
@@ -345,36 +323,10 @@ def get_coordinates(
345
323
  f"-t {extra_input['Warp']['path'].resolve()};",
346
324
  ]
347
325
  # Call antsApplyTransformsToPoints
348
- apply_transforms_to_points_cmd_str = " ".join(
349
- apply_transforms_to_points_cmd
350
- )
351
- logger.info(
352
- "antsApplyTransformsToPoints command to be executed: "
353
- f"{apply_transforms_to_points_cmd_str}"
354
- )
355
- apply_transforms_to_points_process = subprocess.run(
356
- # string needed with shell=True
357
- apply_transforms_to_points_cmd_str,
358
- stdin=subprocess.DEVNULL,
359
- stdout=subprocess.PIPE,
360
- stderr=subprocess.STDOUT,
361
- shell=True, # needed for respecting $PATH
362
- check=False,
326
+ run_ext_cmd(
327
+ name="antsApplyTransformsToPoints",
328
+ cmd=apply_transforms_to_points_cmd,
363
329
  )
364
- if apply_transforms_to_points_process.returncode == 0:
365
- logger.info(
366
- "antsApplyTransformsToPoints succeeded with the following "
367
- f"output: {apply_transforms_to_points_process.stdout}"
368
- )
369
- else:
370
- raise_error(
371
- msg=(
372
- "antsApplyTransformsToPoints failed with the "
373
- "following error: "
374
- f"{apply_transforms_to_points_process.stdout}"
375
- ),
376
- klass=RuntimeError,
377
- )
378
330
 
379
331
  # Load coordinates
380
332
  seeds = np.loadtxt(
junifer/data/masks.py CHANGED
@@ -4,7 +4,6 @@
4
4
  # Synchon Mandal <s.mandal@fz-juelich.de>
5
5
  # License: AGPL
6
6
 
7
- import subprocess
8
7
  import typing
9
8
  from pathlib import Path
10
9
  from typing import (
@@ -30,7 +29,7 @@ from nilearn.masking import (
30
29
  )
31
30
 
32
31
  from ..pipeline import WorkDirManager
33
- from ..utils.logging import logger, raise_error
32
+ from ..utils import logger, raise_error, run_ext_cmd
34
33
  from .utils import closest_resolution
35
34
 
36
35
 
@@ -201,8 +200,7 @@ def get_mask( # noqa: C901
201
200
  RuntimeError
202
201
  If masks are in different spaces and they need to be intersected /
203
202
  unionized or
204
- if warp / transformation file extension is not ".mat" or ".h5" or
205
- if external tool execution failed.
203
+ if warp / transformation file extension is not ".mat" or ".h5".
206
204
  ValueError
207
205
  If extra key is provided in addition to mask name in ``masks`` or
208
206
  if no mask is provided or
@@ -384,30 +382,8 @@ def get_mask( # noqa: C901
384
382
  f"-o {warped_mask_path.resolve()}",
385
383
  ]
386
384
  # Call applywarp
387
- applywarp_cmd_str = " ".join(applywarp_cmd)
388
- logger.info(
389
- f"applywarp command to be executed: {applywarp_cmd_str}"
390
- )
391
- applywarp_process = subprocess.run(
392
- applywarp_cmd_str, # string needed with shell=True
393
- stdin=subprocess.DEVNULL,
394
- stdout=subprocess.PIPE,
395
- stderr=subprocess.STDOUT,
396
- shell=True, # needed for respecting $PATH
397
- check=False,
398
- )
399
- # Check for success or failure
400
- if applywarp_process.returncode == 0:
401
- logger.info(
402
- "applywarp succeeded with the following output: "
403
- f"{applywarp_process.stdout}"
404
- )
405
- else:
406
- raise_error(
407
- msg="applywarp failed with the following error: "
408
- f"{applywarp_process.stdout}",
409
- klass=RuntimeError,
410
- )
385
+ run_ext_cmd(name="applywarp", cmd=applywarp_cmd)
386
+
411
387
  elif warp_file_ext == ".h5":
412
388
  logger.debug("Using ANTs for mask warping")
413
389
  # Set antsApplyTransforms command
@@ -423,32 +399,8 @@ def get_mask( # noqa: C901
423
399
  f"-o {warped_mask_path.resolve()}",
424
400
  ]
425
401
  # Call antsApplyTransforms
426
- apply_transforms_cmd_str = " ".join(apply_transforms_cmd)
427
- logger.info(
428
- "antsApplyTransforms command to be executed: "
429
- f"{apply_transforms_cmd_str}"
430
- )
431
- apply_transforms_process = subprocess.run(
432
- apply_transforms_cmd_str, # string needed with shell=True
433
- stdin=subprocess.DEVNULL,
434
- stdout=subprocess.PIPE,
435
- stderr=subprocess.STDOUT,
436
- shell=True, # needed for respecting $PATH
437
- check=False,
438
- )
439
- if apply_transforms_process.returncode == 0:
440
- logger.info(
441
- "antsApplyTransforms succeeded with the following output: "
442
- f"{apply_transforms_process.stdout}"
443
- )
444
- else:
445
- raise_error(
446
- msg=(
447
- "antsApplyTransforms failed with the following error: "
448
- f"{apply_transforms_process.stdout}"
449
- ),
450
- klass=RuntimeError,
451
- )
402
+ run_ext_cmd(name="antsApplyTransforms", cmd=apply_transforms_cmd)
403
+
452
404
  else:
453
405
  raise_error(
454
406
  msg=(
@@ -7,7 +7,6 @@
7
7
 
8
8
  import io
9
9
  import shutil
10
- import subprocess
11
10
  import tarfile
12
11
  import tempfile
13
12
  import typing
@@ -23,7 +22,7 @@ from nilearn import datasets, image
23
22
  from requests.exceptions import ConnectionError, HTTPError, ReadTimeout
24
23
 
25
24
  from ..pipeline import WorkDirManager
26
- from ..utils.logging import logger, raise_error, warn_with_log
25
+ from ..utils import logger, raise_error, run_ext_cmd, warn_with_log
27
26
  from .utils import closest_resolution
28
27
 
29
28
 
@@ -232,8 +231,7 @@ def get_parcellation(
232
231
  ------
233
232
  RuntimeError
234
233
  If parcellations are in different spaces and they need to be merged or
235
- if warp / transformation file extension is not ".mat" or ".h5" or
236
- if external tool execution failed.
234
+ if warp / transformation file extension is not ".mat" or ".h5".
237
235
  ValueError
238
236
  If ``extra_input`` is None when ``target_data``'s space is native.
239
237
 
@@ -324,30 +322,8 @@ def get_parcellation(
324
322
  f"-o {warped_parcellation_path.resolve()}",
325
323
  ]
326
324
  # Call applywarp
327
- applywarp_cmd_str = " ".join(applywarp_cmd)
328
- logger.info(
329
- f"applywarp command to be executed: {applywarp_cmd_str}"
330
- )
331
- applywarp_process = subprocess.run(
332
- applywarp_cmd_str, # string needed with shell=True
333
- stdin=subprocess.DEVNULL,
334
- stdout=subprocess.PIPE,
335
- stderr=subprocess.STDOUT,
336
- shell=True, # needed for respecting $PATH
337
- check=False,
338
- )
339
- # Check for success or failure
340
- if applywarp_process.returncode == 0:
341
- logger.info(
342
- "applywarp succeeded with the following output: "
343
- f"{applywarp_process.stdout}"
344
- )
345
- else:
346
- raise_error(
347
- msg="applywarp failed with the following error: "
348
- f"{applywarp_process.stdout}",
349
- klass=RuntimeError,
350
- )
325
+ run_ext_cmd(name="applywarp", cmd=applywarp_cmd)
326
+
351
327
  elif warp_file_ext == ".h5":
352
328
  logger.debug("Using ANTs for parcellation warping")
353
329
  # Set antsApplyTransforms command
@@ -363,32 +339,8 @@ def get_parcellation(
363
339
  f"-o {warped_parcellation_path.resolve()}",
364
340
  ]
365
341
  # Call antsApplyTransforms
366
- apply_transforms_cmd_str = " ".join(apply_transforms_cmd)
367
- logger.info(
368
- "antsApplyTransforms command to be executed: "
369
- f"{apply_transforms_cmd_str}"
370
- )
371
- apply_transforms_process = subprocess.run(
372
- apply_transforms_cmd_str, # string needed with shell=True
373
- stdin=subprocess.DEVNULL,
374
- stdout=subprocess.PIPE,
375
- stderr=subprocess.STDOUT,
376
- shell=True, # needed for respecting $PATH
377
- check=False,
378
- )
379
- if apply_transforms_process.returncode == 0:
380
- logger.info(
381
- "antsApplyTransforms succeeded with the following output: "
382
- f"{apply_transforms_process.stdout}"
383
- )
384
- else:
385
- raise_error(
386
- msg=(
387
- "antsApplyTransforms failed with the following error: "
388
- f"{apply_transforms_process.stdout}"
389
- ),
390
- klass=RuntimeError,
391
- )
342
+ run_ext_cmd(name="antsApplyTransforms", cmd=apply_transforms_cmd)
343
+
392
344
  else:
393
345
  raise_error(
394
346
  msg=(
@@ -4,11 +4,10 @@
4
4
  # Federico Raimondo <f.raimondo@fz-juelich.de>
5
5
  # License: AGPL
6
6
 
7
- import subprocess
8
7
  import typing
9
8
  from functools import lru_cache
10
9
  from pathlib import Path
11
- from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple, Union, cast
10
+ from typing import TYPE_CHECKING, Any, Dict, Optional, Tuple, Union
12
11
 
13
12
  import nibabel as nib
14
13
  import numpy as np
@@ -17,7 +16,7 @@ from scipy.fft import fft, fftfreq
17
16
 
18
17
  from ...pipeline import WorkDirManager
19
18
  from ...pipeline.singleton import singleton
20
- from ...utils import logger, raise_error
19
+ from ...utils import logger, run_ext_cmd
21
20
 
22
21
 
23
22
  if TYPE_CHECKING:
@@ -54,42 +53,6 @@ class ALFFEstimator:
54
53
  if self.temp_dir_path is not None:
55
54
  WorkDirManager().delete_tempdir(self.temp_dir_path)
56
55
 
57
- @staticmethod
58
- def _run_afni_cmd(cmd: str) -> None:
59
- """Run AFNI command.
60
-
61
- Parameters
62
- ----------
63
- cmd : str
64
- AFNI command to be executed.
65
-
66
- Raises
67
- ------
68
- RuntimeError
69
- If AFNI command fails.
70
-
71
- """
72
- logger.info(f"AFNI command to be executed: {cmd}")
73
- process = subprocess.run(
74
- cmd,
75
- stdin=subprocess.DEVNULL,
76
- stdout=subprocess.PIPE,
77
- stderr=subprocess.STDOUT,
78
- shell=True,
79
- check=False,
80
- )
81
- if process.returncode == 0:
82
- logger.info(
83
- "AFNI command succeeded with the following output: "
84
- f"{process.stdout}"
85
- )
86
- else:
87
- raise_error(
88
- msg="AFNI command failed with the following error: "
89
- f"{process.stdout}",
90
- klass=RuntimeError,
91
- )
92
-
93
56
  def _compute_alff_afni(
94
57
  self,
95
58
  data: Union["Nifti1Image", "Nifti2Image"],
@@ -121,11 +84,6 @@ class ALFFEstimator:
121
84
  pathlib.Path
122
85
  The path to the fALFF map as NIfTI.
123
86
 
124
- Raises
125
- ------
126
- RuntimeError
127
- If the AFNI commands fails due to some issues.
128
-
129
87
  """
130
88
  # Note: self.temp_dir_path is sure to exist before proceeding, so
131
89
  # types checks are ignored further on.
@@ -150,31 +108,36 @@ class ALFFEstimator:
150
108
  self.temp_dir_path / "temp_falff" # type: ignore
151
109
  )
152
110
 
153
- bp_cmd = (
154
- "3dRSFC "
155
- f"-prefix {falff_afni_out_path_prefix.resolve()} "
156
- f"-input {nifti_in_file_path.resolve()} "
157
- f"-band {highpass} {lowpass} "
158
- "-no_rsfa -nosat -nodetrend "
159
- )
111
+ # Set 3dRSFC command
112
+ bp_cmd = [
113
+ "3dRSFC",
114
+ f"-prefix {falff_afni_out_path_prefix.resolve()}",
115
+ f"-input {nifti_in_file_path.resolve()}",
116
+ f"-band {highpass} {lowpass}",
117
+ "-no_rsfa -nosat -nodetrend",
118
+ ]
160
119
  if tr is not None:
161
- bp_cmd += f"-dt {tr} "
162
- self._run_afni_cmd(bp_cmd)
163
-
164
- # Convert afni's output to nifti
165
- convert_cmd = (
166
- "3dAFNItoNIFTI "
167
- f"-prefix {alff_fname.resolve()} "
168
- f"{falff_afni_out_path_prefix}_ALFF+tlrc.BRIK "
169
- )
170
- self._run_afni_cmd(convert_cmd)
171
-
172
- convert_cmd = (
173
- "3dAFNItoNIFTI "
174
- f"-prefix {falff_fname.resolve()} "
175
- f"{falff_afni_out_path_prefix}_fALFF+tlrc.BRIK "
176
- )
177
- self._run_afni_cmd(convert_cmd)
120
+ bp_cmd.append(f"-dt {tr}")
121
+ # Call 3dRSFC
122
+ run_ext_cmd(name="3dRSFC", cmd=bp_cmd)
123
+
124
+ # Convert alff output to nifti
125
+ convert_alff_cmd = [
126
+ "3dAFNItoNIFTI",
127
+ f"-prefix {alff_fname.resolve()}",
128
+ f"{falff_afni_out_path_prefix}_ALFF+tlrc.BRIK",
129
+ ]
130
+ # Call 3dAFNItoNIFTI
131
+ run_ext_cmd(name="3dAFNItoNIFTI", cmd=convert_alff_cmd)
132
+
133
+ # Convert falff output to nifti
134
+ convert_falff_cmd = [
135
+ "3dAFNItoNIFTI",
136
+ f"-prefix {falff_fname.resolve()}",
137
+ f"{falff_afni_out_path_prefix}_fALFF+tlrc.BRIK",
138
+ ]
139
+ # Call 3dAFNItoNIFTI
140
+ run_ext_cmd(name="3dAFNItoNIFTI", cmd=convert_falff_cmd)
178
141
 
179
142
  # Cleanup intermediate files
180
143
  for fname in self.temp_dir_path.glob("temp_*"): # type: ignore
@@ -183,10 +146,8 @@ class ALFFEstimator:
183
146
  # Load niftis
184
147
  alff_img = nib.load(alff_fname)
185
148
  falff_img = nib.load(falff_fname)
186
- # Cast image type
187
- alff_img = cast("Nifti1Image", alff_img)
188
- falff_img = cast("Nifti1Image", falff_img)
189
- return alff_img, falff_img, alff_fname, falff_fname
149
+
150
+ return alff_img, falff_img, alff_fname, falff_fname # type: ignore
190
151
 
191
152
  def _compute_alff_python(
192
153
  self,
@@ -6,11 +6,10 @@
6
6
 
7
7
 
8
8
  import hashlib
9
- import subprocess
10
9
  from functools import lru_cache
11
10
  from itertools import product
12
11
  from pathlib import Path
13
- from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, cast
12
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple
14
13
 
15
14
  import nibabel as nib
16
15
  import numpy as np
@@ -20,7 +19,7 @@ from scipy.stats import rankdata
20
19
 
21
20
  from ...pipeline import WorkDirManager
22
21
  from ...pipeline.singleton import singleton
23
- from ...utils import logger, raise_error
22
+ from ...utils import logger, raise_error, run_ext_cmd
24
23
 
25
24
 
26
25
  if TYPE_CHECKING:
@@ -112,11 +111,6 @@ class ReHoEstimator:
112
111
  pathlib.Path
113
112
  The path to the ReHo map as NIfTI.
114
113
 
115
- Raises
116
- ------
117
- RuntimeError
118
- If the 3dReHo command fails due to some issue.
119
-
120
114
  Notes
121
115
  -----
122
116
  For more information on the publication, please check [1]_ , and for
@@ -174,30 +168,10 @@ class ReHoEstimator:
174
168
  else:
175
169
  reho_cmd.append(f"-nneigh {nneigh}")
176
170
  # Call 3dReHo
177
- reho_cmd_str = " ".join(reho_cmd)
178
- logger.info(f"3dReHo command to be executed: {reho_cmd_str}")
179
- reho_process = subprocess.run(
180
- reho_cmd_str, # string needed with shell=True
181
- stdin=subprocess.DEVNULL,
182
- stdout=subprocess.PIPE,
183
- stderr=subprocess.STDOUT,
184
- shell=True, # needed for respecting $PATH
185
- check=False,
186
- )
187
- if reho_process.returncode == 0:
188
- logger.info(
189
- "3dReHo succeeded with the following output: "
190
- f"{reho_process.stdout}"
191
- )
192
- else:
193
- raise_error(
194
- msg="3dReHo failed with the following error: "
195
- f"{reho_process.stdout}",
196
- klass=RuntimeError,
197
- )
171
+ run_ext_cmd(name="3dReHo", cmd=reho_cmd)
198
172
 
199
173
  # SHA256 for bypassing memmap
200
- sha256_params = hashlib.sha256(bytes(reho_cmd_str, "utf-8"))
174
+ sha256_params = hashlib.sha256(bytes(" ".join(reho_cmd), "utf-8"))
201
175
  # Create element-scoped tempdir so that the ReHo map is
202
176
  # available later as get_coordinates and the like need it
203
177
  # in ReHoSpheres and the like to transform to other template
@@ -216,27 +190,7 @@ class ReHoEstimator:
216
190
  f"{reho_afni_out_path_prefix}+tlrc.BRIK",
217
191
  ]
218
192
  # Call 3dAFNItoNIFTI
219
- convert_cmd_str = " ".join(convert_cmd)
220
- logger.info(f"3dAFNItoNIFTI command to be executed: {convert_cmd_str}")
221
- convert_process = subprocess.run(
222
- convert_cmd_str, # string needed with shell=True
223
- stdin=subprocess.DEVNULL,
224
- stdout=subprocess.PIPE,
225
- stderr=subprocess.STDOUT,
226
- shell=True, # needed for respecting $PATH
227
- check=False,
228
- )
229
- if convert_process.returncode == 0:
230
- logger.info(
231
- "3dAFNItoNIFTI succeeded with the following output: "
232
- f"{convert_process.stdout}"
233
- )
234
- else:
235
- raise_error(
236
- msg="3dAFNItoNIFTI failed with the following error: "
237
- f"{convert_process.stdout}",
238
- klass=RuntimeError,
239
- )
193
+ run_ext_cmd(name="3dAFNItoNIFTI", cmd=convert_cmd)
240
194
 
241
195
  # Cleanup intermediate files
242
196
  for fname in self.temp_dir_path.glob("reho*"): # type: ignore
@@ -244,9 +198,8 @@ class ReHoEstimator:
244
198
 
245
199
  # Load nifti
246
200
  output_data = nib.load(reho_afni_to_nifti_out_path)
247
- # Stupid casting
248
- output_data = cast("Nifti1Image", output_data)
249
- return output_data, reho_afni_to_nifti_out_path
201
+
202
+ return output_data, reho_afni_to_nifti_out_path # type: ignore
250
203
 
251
204
  def _compute_reho_python(
252
205
  self,
@@ -3,7 +3,6 @@
3
3
  # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
4
  # License: AGPL
5
5
 
6
- import subprocess
7
6
  from pathlib import Path
8
7
  from typing import (
9
8
  TYPE_CHECKING,
@@ -14,14 +13,13 @@ from typing import (
14
13
  Optional,
15
14
  Tuple,
16
15
  Union,
17
- cast,
18
16
  )
19
17
 
20
18
  import nibabel as nib
21
19
  import numpy as np
22
20
 
23
21
  from ...pipeline import WorkDirManager
24
- from ...utils import logger, raise_error
22
+ from ...utils import logger, raise_error, run_ext_cmd
25
23
  from ..base import BasePreprocessor
26
24
 
27
25
 
@@ -125,11 +123,6 @@ class _AntsApplyTransformsWarper(BasePreprocessor):
125
123
  pathlib.Path
126
124
  The path to the resampled reference image.
127
125
 
128
- Raises
129
- ------
130
- RuntimeError
131
- If ANTs command fails.
132
-
133
126
  """
134
127
  # Get the min of the voxel sizes from input and use it as the
135
128
  # resolution
@@ -153,29 +146,7 @@ class _AntsApplyTransformsWarper(BasePreprocessor):
153
146
  "3 3", # Lanczos windowed sinc
154
147
  ]
155
148
  # Call ResampleImage
156
- resample_image_cmd_str = " ".join(resample_image_cmd)
157
- logger.info(
158
- f"ResampleImage command to be executed: {resample_image_cmd_str}"
159
- )
160
- resample_image_process = subprocess.run(
161
- resample_image_cmd_str,
162
- stdin=subprocess.DEVNULL,
163
- stdout=subprocess.PIPE,
164
- stderr=subprocess.STDOUT,
165
- shell=True, # needed for respecting $PATH
166
- check=False,
167
- )
168
- if resample_image_process.returncode == 0:
169
- logger.info(
170
- "ResampleImage succeeded with the following output: "
171
- f"{resample_image_process.stdout}"
172
- )
173
- else:
174
- raise_error(
175
- msg="ResampleImage failed with the following error: "
176
- f"{resample_image_process.stdout}",
177
- klass=RuntimeError,
178
- )
149
+ run_ext_cmd(name="ResampleImage", cmd=resample_image_cmd)
179
150
 
180
151
  # Create a tempfile for warped output
181
152
  apply_transforms_out_path = tempdir / "input_warped.nii.gz"
@@ -192,39 +163,12 @@ class _AntsApplyTransformsWarper(BasePreprocessor):
192
163
  f"-o {apply_transforms_out_path.resolve()}",
193
164
  ]
194
165
  # Call antsApplyTransforms
195
- apply_transforms_cmd_str = " ".join(apply_transforms_cmd)
196
- logger.info(
197
- "antsApplyTransforms command to be executed: "
198
- f"{apply_transforms_cmd_str}"
199
- )
200
- apply_transforms_process = subprocess.run(
201
- apply_transforms_cmd_str, # string needed with shell=True
202
- stdin=subprocess.DEVNULL,
203
- stdout=subprocess.PIPE,
204
- stderr=subprocess.STDOUT,
205
- shell=True, # needed for respecting $PATH
206
- check=False,
207
- )
208
- if apply_transforms_process.returncode == 0:
209
- logger.info(
210
- "antsApplyTransforms succeeded with the following output: "
211
- f"{apply_transforms_process.stdout}"
212
- )
213
- else:
214
- raise_error(
215
- msg=(
216
- "antsApplyTransforms failed with the following error: "
217
- f"{apply_transforms_process.stdout}"
218
- ),
219
- klass=RuntimeError,
220
- )
166
+ run_ext_cmd(name="antsApplyTransforms", cmd=apply_transforms_cmd)
221
167
 
222
168
  # Load nifti
223
169
  output_img = nib.load(apply_transforms_out_path)
224
170
 
225
- # Stupid casting
226
- output_img = cast("Nifti1Image", output_img)
227
- return output_img, resample_image_out_path
171
+ return output_img, resample_image_out_path # type: ignore
228
172
 
229
173
  def preprocess(
230
174
  self,
@@ -3,7 +3,6 @@
3
3
  # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
4
  # License: AGPL
5
5
 
6
- import subprocess
7
6
  from pathlib import Path
8
7
  from typing import (
9
8
  TYPE_CHECKING,
@@ -14,14 +13,13 @@ from typing import (
14
13
  Optional,
15
14
  Tuple,
16
15
  Union,
17
- cast,
18
16
  )
19
17
 
20
18
  import nibabel as nib
21
19
  import numpy as np
22
20
 
23
21
  from ...pipeline import WorkDirManager
24
- from ...utils import logger, raise_error
22
+ from ...utils import logger, raise_error, run_ext_cmd
25
23
  from ..base import BasePreprocessor
26
24
 
27
25
 
@@ -125,11 +123,6 @@ class _ApplyWarper(BasePreprocessor):
125
123
  pathlib.Path
126
124
  The path to the resampled reference image.
127
125
 
128
- Raises
129
- ------
130
- RuntimeError
131
- If FSL commands fail.
132
-
133
126
  """
134
127
  # Get the min of the voxel sizes from input and use it as the
135
128
  # resolution
@@ -150,29 +143,7 @@ class _ApplyWarper(BasePreprocessor):
150
143
  f"-out {flirt_out_path.resolve()}",
151
144
  ]
152
145
  # Call flirt
153
- flirt_cmd_str = " ".join(flirt_cmd)
154
- logger.info(f"flirt command to be executed: {flirt_cmd_str}")
155
- flirt_process = subprocess.run(
156
- flirt_cmd_str,
157
- stdin=subprocess.DEVNULL,
158
- stdout=subprocess.PIPE,
159
- stderr=subprocess.STDOUT,
160
- shell=True, # needed for respecting $PATH
161
- check=False,
162
- )
163
- if flirt_process.returncode == 0:
164
- logger.info(
165
- "flirt succeeded with the following output: "
166
- f"{flirt_process.stdout}"
167
- )
168
- else:
169
- raise_error(
170
- msg="flirt failed with the following error: "
171
- f"{flirt_process.stdout}",
172
- klass=RuntimeError,
173
- )
174
-
175
- # TODO(synchon): Modify reference or not?
146
+ run_ext_cmd(name="flirt", cmd=flirt_cmd)
176
147
 
177
148
  # Create a tempfile for warped output
178
149
  applywarp_out_path = tempdir / "input_warped.nii.gz"
@@ -186,34 +157,12 @@ class _ApplyWarper(BasePreprocessor):
186
157
  f"-o {applywarp_out_path.resolve()}",
187
158
  ]
188
159
  # Call applywarp
189
- applywarp_cmd_str = " ".join(applywarp_cmd)
190
- logger.info(f"applywarp command to be executed: {applywarp_cmd_str}")
191
- applywarp_process = subprocess.run(
192
- applywarp_cmd_str, # string needed with shell=True
193
- stdin=subprocess.DEVNULL,
194
- stdout=subprocess.PIPE,
195
- stderr=subprocess.STDOUT,
196
- shell=True, # needed for respecting $PATH
197
- check=False,
198
- )
199
- if applywarp_process.returncode == 0:
200
- logger.info(
201
- "applywarp succeeded with the following output: "
202
- f"{applywarp_process.stdout}"
203
- )
204
- else:
205
- raise_error(
206
- msg="applywarp failed with the following error: "
207
- f"{applywarp_process.stdout}",
208
- klass=RuntimeError,
209
- )
160
+ run_ext_cmd(name="applywarp", cmd=applywarp_cmd)
210
161
 
211
162
  # Load nifti
212
163
  output_img = nib.load(applywarp_out_path)
213
164
 
214
- # Stupid casting
215
- output_img = cast("Nifti1Image", output_img)
216
- return output_img, flirt_out_path
165
+ return output_img, flirt_out_path # type: ignore
217
166
 
218
167
  def preprocess(
219
168
  self,
junifer/utils/__init__.py CHANGED
@@ -6,3 +6,4 @@
6
6
 
7
7
  from .fs import make_executable
8
8
  from .logging import configure_logging, logger, raise_error, warn_with_log
9
+ from .helpers import run_ext_cmd
@@ -0,0 +1,53 @@
1
+ """Provide helper functions for the package."""
2
+
3
+ # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
+ # License: AGPL
5
+
6
+ import subprocess
7
+ from typing import List
8
+
9
+ from .logging import logger, raise_error
10
+
11
+
12
+ def run_ext_cmd(name: str, cmd: List[str]) -> None:
13
+ """Run external command via subprocess.
14
+
15
+ Parameters
16
+ ----------
17
+ name : str
18
+ The name of the command.
19
+ cmd : list of str
20
+ The command to run as list of string.
21
+
22
+ Raises
23
+ ------
24
+ RuntimeError
25
+ If command fails.
26
+
27
+ """
28
+ # Convert list to str
29
+ cmd_str = " ".join(cmd)
30
+ logger.info(f"{name} command to be executed:\n{cmd_str}")
31
+ # Run command via subprocess
32
+ process = subprocess.run(
33
+ cmd_str, # string needed with shell=True
34
+ stdin=subprocess.DEVNULL,
35
+ stdout=subprocess.PIPE,
36
+ stderr=subprocess.STDOUT,
37
+ shell=True, # needed for respecting $PATH
38
+ check=False,
39
+ )
40
+ # Check for success or failure
41
+ if process.returncode == 0:
42
+ logger.info(
43
+ f"{name} command succeeded with the following output:\n"
44
+ f"{process.stdout}"
45
+ )
46
+ else:
47
+ raise_error(
48
+ msg=(
49
+ f"{name} command failed with the following error:\n"
50
+ f"{process.stdout}"
51
+ ),
52
+ klass=RuntimeError,
53
+ )
@@ -0,0 +1,35 @@
1
+ """Provide tests for helper functions."""
2
+
3
+ # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
+ # License: AGPL
5
+
6
+ import logging
7
+
8
+ import pytest
9
+
10
+ from junifer.utils.helpers import run_ext_cmd
11
+
12
+
13
+ def test_run_ext_cmd_success(caplog: pytest.LogCaptureFixture) -> None:
14
+ """Test external command run success.
15
+
16
+ Parameters
17
+ ----------
18
+ caplog : pytest.LogCaptureFixture
19
+ The pytest.LogCaptureFixture object.
20
+
21
+ """
22
+ # Set log capturing at INFO
23
+ with caplog.at_level(logging.INFO):
24
+ # Run external command
25
+ run_ext_cmd(name="pwd", cmd=["pwd"])
26
+ # Check logging message
27
+ assert "executed" in caplog.text
28
+ assert "succeeded" in caplog.text
29
+
30
+
31
+ def test_run_ext_cmd_failure() -> None:
32
+ """Test external command run failure."""
33
+ with pytest.raises(RuntimeError, match="failed"):
34
+ # Run external command
35
+ run_ext_cmd(name="flymetothemoon", cmd=["flymetothemoon"])
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: junifer
3
- Version: 0.0.4.dev517
3
+ Version: 0.0.4.dev530
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>
@@ -1,5 +1,5 @@
1
1
  junifer/__init__.py,sha256=x1UR2jUcrUdm2HNl-3Qvyi4UUrU6ms5qm2qcmNY7zZk,391
2
- junifer/_version.py,sha256=QBJ7nIQfuU9e2GfHlCvw-1zMTxlX-anU-jj0fbWnfiA,428
2
+ junifer/_version.py,sha256=UAZSywn04AiXQwVQkUu_X6dPMnW5TVCTZAN98gzqfqU,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=xScav2mF-Jr8JjVFt8kaHuLpX5l_jVTaQGPgQL3VNvA,12881
@@ -42,9 +42,9 @@ junifer/configs/juseless/datagrabbers/tests/test_ixi_vbm.py,sha256=8jxpNZelXwpJG
42
42
  junifer/configs/juseless/datagrabbers/tests/test_ucla.py,sha256=e-jdvcZ9B0mka6_573JJU_cGwSaUV54U8X_n0UadtJY,3351
43
43
  junifer/configs/juseless/datagrabbers/tests/test_ukb_vbm.py,sha256=b9hjc1mgO--PSRC3id2EzzfE2yWNsuZ2UI47a6sfGZU,1025
44
44
  junifer/data/__init__.py,sha256=oUjOs8_M6fitNb44izxpXf3su1e4pG_vCdjwVYkjZjQ,550
45
- junifer/data/coordinates.py,sha256=tEZmtrlior0RhM07JyE9Mg2-gWOesnreMcDC51ahBf8,14730
46
- junifer/data/masks.py,sha256=MINm4u_g6kQPUWtkWfPAPmZTSfgbY1mVkxtzkapkOFc,19767
47
- junifer/data/parcellations.py,sha256=fAB9Rlcb_NCM-n2lC4CYYD4uUiIfadJ949LL_QNqMV4,58234
45
+ junifer/data/coordinates.py,sha256=GcL95_wzW5t4iNNmRbgD6IwwH-ERMChJK3kWfZ3ORDc,12701
46
+ junifer/data/masks.py,sha256=81v3GhAf9lc_CobV9f6n_vMK1jWZCbeANmopa02XZOQ,17744
47
+ junifer/data/parcellations.py,sha256=72Gv7Rn5Ppyi2z7m9t9cuwS62yocXEL_bG2uoFUyWww,56211
48
48
  junifer/data/utils.py,sha256=K9quLIoWRmm2QFM8Rdy_5bYsWb_XhL0l5Uq_1Sie0kA,1274
49
49
  junifer/data/VOIs/meta/CogAC_VOIs.txt,sha256=Sr5_E712OLdeQRyUcDNM0wLBvZIyO6gc9Q7KkyJHX1A,398
50
50
  junifer/data/VOIs/meta/CogAR_VOIs.txt,sha256=t3NLwEVUZTPP34p15SaB3UInLrQyK-7Qc4iLBuQlZu8,189
@@ -135,7 +135,7 @@ junifer/markers/complexity/tests/test_sample_entropy.py,sha256=3IeDnDgSeFNmUoPxQ
135
135
  junifer/markers/complexity/tests/test_weighted_perm_entropy.py,sha256=M7Qt_SFZSmptMi0cBGh5Merd1_3hPieIddl_pz7MWbs,2088
136
136
  junifer/markers/falff/__init__.py,sha256=QAUIVtaOFWDL7B8xFrDgsmRum7Q0DCENyDYD1cPMJmM,197
137
137
  junifer/markers/falff/falff_base.py,sha256=isHD643TvDFg7YJxpopHSrpJlgUwx2fW0tzJeSio6c8,6323
138
- junifer/markers/falff/falff_estimator.py,sha256=ayXdQWHUyYyeR7NulOPZpYXkjQ2V8HlbHhy-jDKtZI0,12869
138
+ junifer/markers/falff/falff_estimator.py,sha256=U56sp9wfo5T-MOQN79XSiwj3113x-z8wFIMIwrP5KME,11905
139
139
  junifer/markers/falff/falff_parcels.py,sha256=UTADrIl96eO_xZ90LtOIt7tuN2eLDPnfIJghr9HAO88,4550
140
140
  junifer/markers/falff/falff_spheres.py,sha256=XR2pcBRxjyTZ-J7j_HOjL20_2IHgYO0dI9x4LlQFoVE,5086
141
141
  junifer/markers/falff/tests/test_falff_estimator.py,sha256=aVnkFvPqA5mTb9dXegwAJPku8Tf-1jWtDkfXhdcjDj8,8259
@@ -156,7 +156,7 @@ junifer/markers/functional_connectivity/tests/test_functional_connectivity_parce
156
156
  junifer/markers/functional_connectivity/tests/test_functional_connectivity_spheres.py,sha256=KOaMkLf7CEd1H8A92WpZAy6X6VNf6TADzYqsqXqvV4Q,4278
157
157
  junifer/markers/reho/__init__.py,sha256=9IfeAxKEVgMWbhud-8T54Le07I4pR6A29sMKeFtvEPg,189
158
158
  junifer/markers/reho/reho_base.py,sha256=d6oxynZ41EGd7f3zorRww6vMtFYF0PjD6RdAVlLq9BA,3932
159
- junifer/markers/reho/reho_estimator.py,sha256=88Ki-Ysq7MfmODynA_wk-7tvYdggmB_Z5HDa3gaZeoM,19692
159
+ junifer/markers/reho/reho_estimator.py,sha256=vLGQDBs9QMT7E7Oc9e8Jz70CScQ9JmlrDdxbEMAz8WA,17996
160
160
  junifer/markers/reho/reho_parcels.py,sha256=Q-gkB9aO0ncxgEQ68XEQKekpLLu_kXiYC6Xqkv8cdvY,6048
161
161
  junifer/markers/reho/reho_spheres.py,sha256=ng5JzYorEnYmFVlxRMOMwkLNFsq2FlMN4o95B_BBVo0,6565
162
162
  junifer/markers/reho/tests/test_reho_estimator.py,sha256=V_584X3I5a-XXAIs8YtR4TMuSqhMvGd5E1vcoDj8gQA,10168
@@ -193,13 +193,13 @@ junifer/preprocess/__init__.py,sha256=-3exohZnw-gJ-MjVM63WcXzBW1mbSetEVozcDfs5et
193
193
  junifer/preprocess/base.py,sha256=syiNqI8pUjoGyShZSjs_RTsd5VHhwoqzIfPfFstr4f4,6230
194
194
  junifer/preprocess/bold_warper.py,sha256=KOYCPCTJE92yI1juXK-3yl7VUxUhbzqqQxJrCYgk-0E,4572
195
195
  junifer/preprocess/ants/__init__.py,sha256=Uobmbhh6_gOowkF2hQNSQOh3AYeaXzarBXEcLJzhERE,112
196
- junifer/preprocess/ants/ants_apply_transforms_warper.py,sha256=BWXurnmQeeRjfrHUjtVqgofKe9migd6yQsyXC643Yxk,8537
196
+ junifer/preprocess/ants/ants_apply_transforms_warper.py,sha256=V3y9EIGdIeJhJpnEVi123fHTK3R0sv_-OmWY7R_DC1M,6627
197
197
  junifer/preprocess/ants/tests/test_ants_apply_transforms_warper.py,sha256=ibLLISss0o0wg3lqpLhL1oO7MfU_bZF5PBqY3OOd9sg,3737
198
198
  junifer/preprocess/confounds/__init__.py,sha256=EDlcD9jy8O9xluJr6XOnFXtjGCDVqwg6sDIRDMbM8ZU,235
199
199
  junifer/preprocess/confounds/fmriprep_confound_remover.py,sha256=23UJ6miqX0iE3dUMsZ1hzWoJDnMLl6WMlT-k9GFmAAU,21904
200
200
  junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py,sha256=OKACXAHytNrOAFZ5I2UcyfcYz5s2qeu31MZ9K71rWGc,22167
201
201
  junifer/preprocess/fsl/__init__.py,sha256=DerGFQ-dIuX5PT9a_BH6QkIXkJZVymjYy-woXF7tYGc,111
202
- junifer/preprocess/fsl/apply_warper.py,sha256=sUCH06fSIFHp9cOMdlzICOGqo7p0ABjjoPmLbTtZO54,7924
202
+ junifer/preprocess/fsl/apply_warper.py,sha256=_HU1-63A32cSQw9eNdgpKN52BFivn6cZaDa0_at-4UY,6215
203
203
  junifer/preprocess/fsl/tests/test_apply_warper.py,sha256=b--MMPlaJw284gJWw-QV8rz6Rb2zmcBjYaY-cb6-uNU,3024
204
204
  junifer/preprocess/tests/test_bold_warper.py,sha256=X4rs-IBu_Oe9wF81Xlh6ih9BCu8SUyDm64lXKk-l9Q8,2831
205
205
  junifer/preprocess/tests/test_preprocess_base.py,sha256=UHuH_YOK7AU3AfApWqgB6YLG-J669BgztuxNSWCtmtI,2560
@@ -225,15 +225,17 @@ junifer/testing/tests/test_spmauditory_datagrabber.py,sha256=1G1emk-Ze59HiNLaYsy
225
225
  junifer/testing/tests/test_testing_registry.py,sha256=oerticBaPRaRZm3yANzInLac0Mqph3Y0aZPQFayu7xA,827
226
226
  junifer/tests/test_main.py,sha256=GMff7jlisGM9_FsiUwWDte43j-KQJGFRYZpwRRqTkd8,373
227
227
  junifer/tests/test_stats.py,sha256=3vPMgYYpWxk8ECDFOMm3-dFBlh4XxjL83SwRBSBAHok,4155
228
- junifer/utils/__init__.py,sha256=ZDPU9ezSKawAJhb-3T67jDf-16QEyF6e7ONyu-lnBtQ,277
228
+ junifer/utils/__init__.py,sha256=sFpsDKbPPtoU3Db3OSO9Vo45u4yE7UfocNaBtD-qvdk,310
229
229
  junifer/utils/fs.py,sha256=Jd9AoV2fIF7pT7KhXsn8T1O1fJ1_SFZgaFuOBAM7DG8,460
230
+ junifer/utils/helpers.py,sha256=Hp3yGZa9x659BCqFTd4keEU1gbHXNAbJ1_lHG1M6lwI,1338
230
231
  junifer/utils/logging.py,sha256=4kH8j9X_J2bMdnBJMldVF95C5sURa5UAsLmSgRaD9Ig,9117
231
232
  junifer/utils/tests/test_fs.py,sha256=WQS7cKlKEZ742CIuiOYYpueeAhY9PqlastfDVpVVtvE,923
233
+ junifer/utils/tests/test_helpers.py,sha256=k5qqfxK8dFyuewTJyR1Qn6-nFaYNuVr0ysc18bfPjyU,929
232
234
  junifer/utils/tests/test_logging.py,sha256=l8oo-AiBV7H6_IzlsNcj__cLeZBUvgIGoaMszD9VaJg,7754
233
- junifer-0.0.4.dev517.dist-info/AUTHORS.rst,sha256=rmULKpchpSol4ExWFdm-qu4fkpSZPYqIESVJBZtGb6E,163
234
- junifer-0.0.4.dev517.dist-info/LICENSE.md,sha256=MqCnOBu8uXsEOzRZWh9EBVfVz-kE9NkXcLCrtGXo2yU,34354
235
- junifer-0.0.4.dev517.dist-info/METADATA,sha256=RzDBLpqCrGN-QuGdRMQThJ37K9uGxPXJa2H8TZXGufw,7745
236
- junifer-0.0.4.dev517.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
237
- junifer-0.0.4.dev517.dist-info/entry_points.txt,sha256=DxFvKq0pOqRunAK0FxwJcoDfV1-dZvsFDpD5HRqSDhw,48
238
- junifer-0.0.4.dev517.dist-info/top_level.txt,sha256=4bAq1R2QFQ4b3hohjys2JBvxrl0GKk5LNFzYvz9VGcA,8
239
- junifer-0.0.4.dev517.dist-info/RECORD,,
235
+ junifer-0.0.4.dev530.dist-info/AUTHORS.rst,sha256=rmULKpchpSol4ExWFdm-qu4fkpSZPYqIESVJBZtGb6E,163
236
+ junifer-0.0.4.dev530.dist-info/LICENSE.md,sha256=MqCnOBu8uXsEOzRZWh9EBVfVz-kE9NkXcLCrtGXo2yU,34354
237
+ junifer-0.0.4.dev530.dist-info/METADATA,sha256=7NtLR9A6bZqYUGw4dYhUS1oA3Bj-r1dEKbz85m560Y4,7745
238
+ junifer-0.0.4.dev530.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
239
+ junifer-0.0.4.dev530.dist-info/entry_points.txt,sha256=DxFvKq0pOqRunAK0FxwJcoDfV1-dZvsFDpD5HRqSDhw,48
240
+ junifer-0.0.4.dev530.dist-info/top_level.txt,sha256=4bAq1R2QFQ4b3hohjys2JBvxrl0GKk5LNFzYvz9VGcA,8
241
+ junifer-0.0.4.dev530.dist-info/RECORD,,