junifer 0.0.5.dev242__py3-none-any.whl → 0.0.6__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (279) hide show
  1. junifer/__init__.py +2 -31
  2. junifer/__init__.pyi +37 -0
  3. junifer/_version.py +9 -4
  4. junifer/api/__init__.py +3 -5
  5. junifer/api/__init__.pyi +4 -0
  6. junifer/api/decorators.py +14 -19
  7. junifer/api/functions.py +165 -109
  8. junifer/api/py.typed +0 -0
  9. junifer/api/queue_context/__init__.py +2 -4
  10. junifer/api/queue_context/__init__.pyi +5 -0
  11. junifer/api/queue_context/gnu_parallel_local_adapter.py +22 -6
  12. junifer/api/queue_context/htcondor_adapter.py +23 -6
  13. junifer/api/queue_context/py.typed +0 -0
  14. junifer/api/queue_context/tests/test_gnu_parallel_local_adapter.py +3 -3
  15. junifer/api/queue_context/tests/test_htcondor_adapter.py +3 -3
  16. junifer/api/tests/test_functions.py +168 -74
  17. junifer/cli/__init__.py +24 -0
  18. junifer/cli/__init__.pyi +3 -0
  19. junifer/{api → cli}/cli.py +141 -125
  20. junifer/cli/parser.py +235 -0
  21. junifer/cli/py.typed +0 -0
  22. junifer/{api → cli}/tests/test_cli.py +8 -8
  23. junifer/{api/tests/test_api_utils.py → cli/tests/test_cli_utils.py} +5 -4
  24. junifer/{api → cli}/tests/test_parser.py +2 -2
  25. junifer/{api → cli}/utils.py +6 -16
  26. junifer/configs/juseless/__init__.py +2 -2
  27. junifer/configs/juseless/__init__.pyi +3 -0
  28. junifer/configs/juseless/datagrabbers/__init__.py +2 -12
  29. junifer/configs/juseless/datagrabbers/__init__.pyi +13 -0
  30. junifer/configs/juseless/datagrabbers/ixi_vbm.py +2 -2
  31. junifer/configs/juseless/datagrabbers/py.typed +0 -0
  32. junifer/configs/juseless/datagrabbers/tests/test_ucla.py +2 -2
  33. junifer/configs/juseless/datagrabbers/ucla.py +4 -4
  34. junifer/configs/juseless/py.typed +0 -0
  35. junifer/conftest.py +25 -0
  36. junifer/data/__init__.py +2 -42
  37. junifer/data/__init__.pyi +29 -0
  38. junifer/data/_dispatch.py +248 -0
  39. junifer/data/coordinates/__init__.py +9 -0
  40. junifer/data/coordinates/__init__.pyi +5 -0
  41. junifer/data/coordinates/_ants_coordinates_warper.py +104 -0
  42. junifer/data/coordinates/_coordinates.py +385 -0
  43. junifer/data/coordinates/_fsl_coordinates_warper.py +81 -0
  44. junifer/data/{tests → coordinates/tests}/test_coordinates.py +26 -33
  45. junifer/data/masks/__init__.py +9 -0
  46. junifer/data/masks/__init__.pyi +6 -0
  47. junifer/data/masks/_ants_mask_warper.py +177 -0
  48. junifer/data/masks/_fsl_mask_warper.py +106 -0
  49. junifer/data/masks/_masks.py +802 -0
  50. junifer/data/{tests → masks/tests}/test_masks.py +67 -63
  51. junifer/data/parcellations/__init__.py +9 -0
  52. junifer/data/parcellations/__init__.pyi +6 -0
  53. junifer/data/parcellations/_ants_parcellation_warper.py +166 -0
  54. junifer/data/parcellations/_fsl_parcellation_warper.py +89 -0
  55. junifer/data/parcellations/_parcellations.py +1388 -0
  56. junifer/data/{tests → parcellations/tests}/test_parcellations.py +165 -295
  57. junifer/data/pipeline_data_registry_base.py +76 -0
  58. junifer/data/py.typed +0 -0
  59. junifer/data/template_spaces.py +44 -79
  60. junifer/data/tests/test_data_utils.py +1 -2
  61. junifer/data/tests/test_template_spaces.py +8 -4
  62. junifer/data/utils.py +109 -4
  63. junifer/datagrabber/__init__.py +2 -26
  64. junifer/datagrabber/__init__.pyi +27 -0
  65. junifer/datagrabber/aomic/__init__.py +2 -4
  66. junifer/datagrabber/aomic/__init__.pyi +5 -0
  67. junifer/datagrabber/aomic/id1000.py +81 -52
  68. junifer/datagrabber/aomic/piop1.py +83 -55
  69. junifer/datagrabber/aomic/piop2.py +85 -56
  70. junifer/datagrabber/aomic/py.typed +0 -0
  71. junifer/datagrabber/aomic/tests/test_id1000.py +19 -12
  72. junifer/datagrabber/aomic/tests/test_piop1.py +52 -18
  73. junifer/datagrabber/aomic/tests/test_piop2.py +50 -17
  74. junifer/datagrabber/base.py +22 -18
  75. junifer/datagrabber/datalad_base.py +71 -34
  76. junifer/datagrabber/dmcc13_benchmark.py +31 -18
  77. junifer/datagrabber/hcp1200/__init__.py +2 -3
  78. junifer/datagrabber/hcp1200/__init__.pyi +4 -0
  79. junifer/datagrabber/hcp1200/datalad_hcp1200.py +3 -3
  80. junifer/datagrabber/hcp1200/hcp1200.py +26 -15
  81. junifer/datagrabber/hcp1200/py.typed +0 -0
  82. junifer/datagrabber/hcp1200/tests/test_hcp1200.py +8 -2
  83. junifer/datagrabber/multiple.py +14 -9
  84. junifer/datagrabber/pattern.py +132 -96
  85. junifer/datagrabber/pattern_validation_mixin.py +206 -94
  86. junifer/datagrabber/py.typed +0 -0
  87. junifer/datagrabber/tests/test_datalad_base.py +27 -12
  88. junifer/datagrabber/tests/test_dmcc13_benchmark.py +28 -11
  89. junifer/datagrabber/tests/test_multiple.py +48 -2
  90. junifer/datagrabber/tests/test_pattern_datalad.py +1 -1
  91. junifer/datagrabber/tests/test_pattern_validation_mixin.py +6 -6
  92. junifer/datareader/__init__.py +2 -2
  93. junifer/datareader/__init__.pyi +3 -0
  94. junifer/datareader/default.py +6 -6
  95. junifer/datareader/py.typed +0 -0
  96. junifer/external/nilearn/__init__.py +2 -3
  97. junifer/external/nilearn/__init__.pyi +4 -0
  98. junifer/external/nilearn/junifer_connectivity_measure.py +25 -17
  99. junifer/external/nilearn/junifer_nifti_spheres_masker.py +4 -4
  100. junifer/external/nilearn/py.typed +0 -0
  101. junifer/external/nilearn/tests/test_junifer_connectivity_measure.py +17 -16
  102. junifer/external/nilearn/tests/test_junifer_nifti_spheres_masker.py +2 -3
  103. junifer/markers/__init__.py +2 -38
  104. junifer/markers/__init__.pyi +37 -0
  105. junifer/markers/base.py +11 -14
  106. junifer/markers/brainprint.py +12 -14
  107. junifer/markers/complexity/__init__.py +2 -18
  108. junifer/markers/complexity/__init__.pyi +17 -0
  109. junifer/markers/complexity/complexity_base.py +9 -11
  110. junifer/markers/complexity/hurst_exponent.py +7 -7
  111. junifer/markers/complexity/multiscale_entropy_auc.py +7 -7
  112. junifer/markers/complexity/perm_entropy.py +7 -7
  113. junifer/markers/complexity/py.typed +0 -0
  114. junifer/markers/complexity/range_entropy.py +7 -7
  115. junifer/markers/complexity/range_entropy_auc.py +7 -7
  116. junifer/markers/complexity/sample_entropy.py +7 -7
  117. junifer/markers/complexity/tests/test_complexity_base.py +1 -1
  118. junifer/markers/complexity/tests/test_hurst_exponent.py +5 -5
  119. junifer/markers/complexity/tests/test_multiscale_entropy_auc.py +5 -5
  120. junifer/markers/complexity/tests/test_perm_entropy.py +5 -5
  121. junifer/markers/complexity/tests/test_range_entropy.py +5 -5
  122. junifer/markers/complexity/tests/test_range_entropy_auc.py +5 -5
  123. junifer/markers/complexity/tests/test_sample_entropy.py +5 -5
  124. junifer/markers/complexity/tests/test_weighted_perm_entropy.py +5 -5
  125. junifer/markers/complexity/weighted_perm_entropy.py +7 -7
  126. junifer/markers/ets_rss.py +12 -11
  127. junifer/markers/falff/__init__.py +2 -3
  128. junifer/markers/falff/__init__.pyi +4 -0
  129. junifer/markers/falff/_afni_falff.py +38 -45
  130. junifer/markers/falff/_junifer_falff.py +16 -19
  131. junifer/markers/falff/falff_base.py +7 -11
  132. junifer/markers/falff/falff_parcels.py +9 -9
  133. junifer/markers/falff/falff_spheres.py +8 -8
  134. junifer/markers/falff/py.typed +0 -0
  135. junifer/markers/falff/tests/test_falff_spheres.py +3 -1
  136. junifer/markers/functional_connectivity/__init__.py +2 -12
  137. junifer/markers/functional_connectivity/__init__.pyi +13 -0
  138. junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +9 -8
  139. junifer/markers/functional_connectivity/edge_functional_connectivity_parcels.py +8 -8
  140. junifer/markers/functional_connectivity/edge_functional_connectivity_spheres.py +7 -7
  141. junifer/markers/functional_connectivity/functional_connectivity_base.py +13 -12
  142. junifer/markers/functional_connectivity/functional_connectivity_parcels.py +8 -8
  143. junifer/markers/functional_connectivity/functional_connectivity_spheres.py +7 -7
  144. junifer/markers/functional_connectivity/py.typed +0 -0
  145. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_parcels.py +1 -2
  146. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_spheres.py +1 -2
  147. junifer/markers/functional_connectivity/tests/test_functional_connectivity_parcels.py +6 -6
  148. junifer/markers/functional_connectivity/tests/test_functional_connectivity_spheres.py +5 -5
  149. junifer/markers/parcel_aggregation.py +22 -17
  150. junifer/markers/py.typed +0 -0
  151. junifer/markers/reho/__init__.py +2 -3
  152. junifer/markers/reho/__init__.pyi +4 -0
  153. junifer/markers/reho/_afni_reho.py +29 -35
  154. junifer/markers/reho/_junifer_reho.py +13 -14
  155. junifer/markers/reho/py.typed +0 -0
  156. junifer/markers/reho/reho_base.py +7 -11
  157. junifer/markers/reho/reho_parcels.py +10 -10
  158. junifer/markers/reho/reho_spheres.py +9 -9
  159. junifer/markers/sphere_aggregation.py +22 -17
  160. junifer/markers/temporal_snr/__init__.py +2 -3
  161. junifer/markers/temporal_snr/__init__.pyi +4 -0
  162. junifer/markers/temporal_snr/py.typed +0 -0
  163. junifer/markers/temporal_snr/temporal_snr_base.py +11 -10
  164. junifer/markers/temporal_snr/temporal_snr_parcels.py +8 -8
  165. junifer/markers/temporal_snr/temporal_snr_spheres.py +7 -7
  166. junifer/markers/tests/test_ets_rss.py +3 -3
  167. junifer/markers/tests/test_parcel_aggregation.py +24 -24
  168. junifer/markers/tests/test_sphere_aggregation.py +6 -6
  169. junifer/markers/utils.py +3 -3
  170. junifer/onthefly/__init__.py +2 -1
  171. junifer/onthefly/_brainprint.py +138 -0
  172. junifer/onthefly/read_transform.py +5 -8
  173. junifer/pipeline/__init__.py +2 -10
  174. junifer/pipeline/__init__.pyi +13 -0
  175. junifer/{markers/collection.py → pipeline/marker_collection.py} +8 -14
  176. junifer/pipeline/pipeline_component_registry.py +294 -0
  177. junifer/pipeline/pipeline_step_mixin.py +15 -11
  178. junifer/pipeline/py.typed +0 -0
  179. junifer/{markers/tests/test_collection.py → pipeline/tests/test_marker_collection.py} +2 -3
  180. junifer/pipeline/tests/test_pipeline_component_registry.py +200 -0
  181. junifer/pipeline/tests/test_pipeline_step_mixin.py +36 -37
  182. junifer/pipeline/tests/test_update_meta_mixin.py +4 -4
  183. junifer/pipeline/tests/test_workdir_manager.py +43 -0
  184. junifer/pipeline/update_meta_mixin.py +21 -17
  185. junifer/pipeline/utils.py +6 -6
  186. junifer/pipeline/workdir_manager.py +19 -5
  187. junifer/preprocess/__init__.py +2 -10
  188. junifer/preprocess/__init__.pyi +11 -0
  189. junifer/preprocess/base.py +10 -10
  190. junifer/preprocess/confounds/__init__.py +2 -2
  191. junifer/preprocess/confounds/__init__.pyi +3 -0
  192. junifer/preprocess/confounds/fmriprep_confound_remover.py +243 -64
  193. junifer/preprocess/confounds/py.typed +0 -0
  194. junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py +121 -14
  195. junifer/preprocess/py.typed +0 -0
  196. junifer/preprocess/smoothing/__init__.py +2 -2
  197. junifer/preprocess/smoothing/__init__.pyi +3 -0
  198. junifer/preprocess/smoothing/_afni_smoothing.py +40 -40
  199. junifer/preprocess/smoothing/_fsl_smoothing.py +22 -32
  200. junifer/preprocess/smoothing/_nilearn_smoothing.py +35 -14
  201. junifer/preprocess/smoothing/py.typed +0 -0
  202. junifer/preprocess/smoothing/smoothing.py +11 -13
  203. junifer/preprocess/warping/__init__.py +2 -2
  204. junifer/preprocess/warping/__init__.pyi +3 -0
  205. junifer/preprocess/warping/_ants_warper.py +136 -32
  206. junifer/preprocess/warping/_fsl_warper.py +73 -22
  207. junifer/preprocess/warping/py.typed +0 -0
  208. junifer/preprocess/warping/space_warper.py +39 -11
  209. junifer/preprocess/warping/tests/test_space_warper.py +5 -9
  210. junifer/py.typed +0 -0
  211. junifer/stats.py +5 -5
  212. junifer/storage/__init__.py +2 -10
  213. junifer/storage/__init__.pyi +11 -0
  214. junifer/storage/base.py +47 -13
  215. junifer/storage/hdf5.py +95 -33
  216. junifer/storage/pandas_base.py +12 -11
  217. junifer/storage/py.typed +0 -0
  218. junifer/storage/sqlite.py +11 -11
  219. junifer/storage/tests/test_hdf5.py +86 -4
  220. junifer/storage/tests/test_sqlite.py +2 -2
  221. junifer/storage/tests/test_storage_base.py +5 -2
  222. junifer/storage/tests/test_utils.py +33 -7
  223. junifer/storage/utils.py +95 -9
  224. junifer/testing/__init__.py +2 -3
  225. junifer/testing/__init__.pyi +4 -0
  226. junifer/testing/datagrabbers.py +10 -11
  227. junifer/testing/py.typed +0 -0
  228. junifer/testing/registry.py +4 -7
  229. junifer/testing/tests/test_testing_registry.py +9 -17
  230. junifer/tests/test_stats.py +2 -2
  231. junifer/typing/__init__.py +9 -0
  232. junifer/typing/__init__.pyi +31 -0
  233. junifer/typing/_typing.py +68 -0
  234. junifer/utils/__init__.py +2 -12
  235. junifer/utils/__init__.pyi +18 -0
  236. junifer/utils/_config.py +110 -0
  237. junifer/utils/_yaml.py +16 -0
  238. junifer/utils/helpers.py +6 -6
  239. junifer/utils/logging.py +117 -8
  240. junifer/utils/py.typed +0 -0
  241. junifer/{pipeline → utils}/singleton.py +19 -14
  242. junifer/utils/tests/test_config.py +59 -0
  243. {junifer-0.0.5.dev242.dist-info → junifer-0.0.6.dist-info}/METADATA +43 -38
  244. junifer-0.0.6.dist-info/RECORD +350 -0
  245. {junifer-0.0.5.dev242.dist-info → junifer-0.0.6.dist-info}/WHEEL +1 -1
  246. junifer-0.0.6.dist-info/entry_points.txt +2 -0
  247. junifer/api/parser.py +0 -118
  248. junifer/data/coordinates.py +0 -408
  249. junifer/data/masks.py +0 -670
  250. junifer/data/parcellations.py +0 -1828
  251. junifer/pipeline/registry.py +0 -177
  252. junifer/pipeline/tests/test_registry.py +0 -150
  253. junifer-0.0.5.dev242.dist-info/RECORD +0 -275
  254. junifer-0.0.5.dev242.dist-info/entry_points.txt +0 -2
  255. /junifer/{api → cli}/tests/data/gmd_mean.yaml +0 -0
  256. /junifer/{api → cli}/tests/data/gmd_mean_htcondor.yaml +0 -0
  257. /junifer/{api → cli}/tests/data/partly_cloudy_agg_mean_tian.yml +0 -0
  258. /junifer/data/{VOIs → coordinates/VOIs}/meta/AutobiographicalMemory_VOIs.txt +0 -0
  259. /junifer/data/{VOIs → coordinates/VOIs}/meta/CogAC_VOIs.txt +0 -0
  260. /junifer/data/{VOIs → coordinates/VOIs}/meta/CogAR_VOIs.txt +0 -0
  261. /junifer/data/{VOIs → coordinates/VOIs}/meta/DMNBuckner_VOIs.txt +0 -0
  262. /junifer/data/{VOIs → coordinates/VOIs}/meta/Dosenbach2010_MNI_VOIs.txt +0 -0
  263. /junifer/data/{VOIs → coordinates/VOIs}/meta/Empathy_VOIs.txt +0 -0
  264. /junifer/data/{VOIs → coordinates/VOIs}/meta/Motor_VOIs.txt +0 -0
  265. /junifer/data/{VOIs → coordinates/VOIs}/meta/MultiTask_VOIs.txt +0 -0
  266. /junifer/data/{VOIs → coordinates/VOIs}/meta/PhysioStress_VOIs.txt +0 -0
  267. /junifer/data/{VOIs → coordinates/VOIs}/meta/Power2011_MNI_VOIs.txt +0 -0
  268. /junifer/data/{VOIs → coordinates/VOIs}/meta/Power2013_MNI_VOIs.tsv +0 -0
  269. /junifer/data/{VOIs → coordinates/VOIs}/meta/Rew_VOIs.txt +0 -0
  270. /junifer/data/{VOIs → coordinates/VOIs}/meta/Somatosensory_VOIs.txt +0 -0
  271. /junifer/data/{VOIs → coordinates/VOIs}/meta/ToM_VOIs.txt +0 -0
  272. /junifer/data/{VOIs → coordinates/VOIs}/meta/VigAtt_VOIs.txt +0 -0
  273. /junifer/data/{VOIs → coordinates/VOIs}/meta/WM_VOIs.txt +0 -0
  274. /junifer/data/{VOIs → coordinates/VOIs}/meta/eMDN_VOIs.txt +0 -0
  275. /junifer/data/{VOIs → coordinates/VOIs}/meta/eSAD_VOIs.txt +0 -0
  276. /junifer/data/{VOIs → coordinates/VOIs}/meta/extDMN_VOIs.txt +0 -0
  277. {junifer-0.0.5.dev242.dist-info → junifer-0.0.6.dist-info/licenses}/AUTHORS.rst +0 -0
  278. {junifer-0.0.5.dev242.dist-info → junifer-0.0.6.dist-info/licenses}/LICENSE.md +0 -0
  279. {junifer-0.0.5.dev242.dist-info → junifer-0.0.6.dist-info}/top_level.txt +0 -0
@@ -6,8 +6,9 @@
6
6
  import shutil
7
7
  import textwrap
8
8
  from pathlib import Path
9
- from typing import Dict, List, Optional, Tuple, Union
9
+ from typing import Optional
10
10
 
11
+ from ...typing import Elements
11
12
  from ...utils import logger, make_executable, raise_error, run_ext_cmd
12
13
  from .queue_context_adapter import QueueContextAdapter
13
14
 
@@ -37,6 +38,9 @@ class GnuParallelLocalAdapter(QueueContextAdapter):
37
38
  virtual environment of any kind (default None).
38
39
  verbose : str, optional
39
40
  The level of verbosity (default "info").
41
+ verbose_datalad : str or None, optional
42
+ The level of verbosity for datalad. If None, will be the same
43
+ as ``verbose`` (default None).
40
44
  submit : bool, optional
41
45
  Whether to submit the jobs (default False).
42
46
 
@@ -60,11 +64,12 @@ class GnuParallelLocalAdapter(QueueContextAdapter):
60
64
  job_name: str,
61
65
  job_dir: Path,
62
66
  yaml_config_path: Path,
63
- elements: List[Union[str, Tuple]],
67
+ elements: Elements,
64
68
  pre_run: Optional[str] = None,
65
69
  pre_collect: Optional[str] = None,
66
- env: Optional[Dict[str, str]] = None,
70
+ env: Optional[dict[str, str]] = None,
67
71
  verbose: str = "info",
72
+ verbose_datalad: Optional[str] = None,
68
73
  submit: bool = False,
69
74
  ) -> None:
70
75
  """Initialize the class."""
@@ -76,6 +81,7 @@ class GnuParallelLocalAdapter(QueueContextAdapter):
76
81
  self._pre_collect = pre_collect
77
82
  self._check_env(env)
78
83
  self._verbose = verbose
84
+ self._verbose_datalad = verbose_datalad
79
85
  self._submit = submit
80
86
 
81
87
  self._log_dir = self._job_dir / "logs"
@@ -86,7 +92,7 @@ class GnuParallelLocalAdapter(QueueContextAdapter):
86
92
  self._run_joblog_path = self._job_dir / f"run_{self._job_name}_joblog"
87
93
  self._elements_file_path = self._job_dir / "elements"
88
94
 
89
- def _check_env(self, env: Optional[Dict[str, str]]) -> None:
95
+ def _check_env(self, env: Optional[dict[str, str]]) -> None:
90
96
  """Check value of env parameter on init.
91
97
 
92
98
  Parameters
@@ -155,6 +161,11 @@ class GnuParallelLocalAdapter(QueueContextAdapter):
155
161
 
156
162
  def run(self) -> str:
157
163
  """Return run commands."""
164
+ verbose_args = f"--verbose {self._verbose}"
165
+ if self._verbose_datalad:
166
+ verbose_args = (
167
+ f"{verbose_args} --verbose-datalad {self._verbose_datalad}"
168
+ )
158
169
  return (
159
170
  f"#!/usr/bin/env {self._shell}\n\n"
160
171
  "# This script is auto-generated by junifer.\n\n"
@@ -169,7 +180,7 @@ class GnuParallelLocalAdapter(QueueContextAdapter):
169
180
  f"{self._job_dir.resolve()!s}/{self._executable} "
170
181
  f"{self._arguments} run "
171
182
  f"{self._yaml_config_path.resolve()!s} "
172
- f"--verbose {self._verbose} "
183
+ f"{verbose_args} "
173
184
  f"--element"
174
185
  )
175
186
 
@@ -184,6 +195,11 @@ class GnuParallelLocalAdapter(QueueContextAdapter):
184
195
 
185
196
  def collect(self) -> str:
186
197
  """Return collect commands."""
198
+ verbose_args = f"--verbose {self._verbose}"
199
+ if self._verbose_datalad:
200
+ verbose_args = (
201
+ f"{verbose_args} --verbose-datalad {self._verbose_datalad}"
202
+ )
187
203
  return (
188
204
  f"#!/usr/bin/env {self._shell}\n\n"
189
205
  "# This script is auto-generated by junifer.\n\n"
@@ -193,7 +209,7 @@ class GnuParallelLocalAdapter(QueueContextAdapter):
193
209
  f"{self._job_dir.resolve()!s}/{self._executable} "
194
210
  f"{self._arguments} collect "
195
211
  f"{self._yaml_config_path.resolve()!s} "
196
- f"--verbose {self._verbose}"
212
+ f"{verbose_args}"
197
213
  )
198
214
 
199
215
  def prepare(self) -> None:
@@ -6,8 +6,9 @@
6
6
  import shutil
7
7
  import textwrap
8
8
  from pathlib import Path
9
- from typing import Dict, List, Optional, Tuple, Union
9
+ from typing import Optional
10
10
 
11
+ from ...typing import Elements
11
12
  from ...utils import logger, make_executable, raise_error, run_ext_cmd
12
13
  from .queue_context_adapter import QueueContextAdapter
13
14
 
@@ -37,6 +38,9 @@ class HTCondorAdapter(QueueContextAdapter):
37
38
  virtual environment of any kind (default None).
38
39
  verbose : str, optional
39
40
  The level of verbosity (default "info").
41
+ verbose_datalad : str or None, optional
42
+ The level of verbosity for datalad. If None, will be the same
43
+ as ``verbose`` (default None).
40
44
  cpus : int, optional
41
45
  The number of CPU cores to use (default 1).
42
46
  mem : str, optional
@@ -78,11 +82,12 @@ class HTCondorAdapter(QueueContextAdapter):
78
82
  job_name: str,
79
83
  job_dir: Path,
80
84
  yaml_config_path: Path,
81
- elements: List[Union[str, Tuple]],
85
+ elements: Elements,
82
86
  pre_run: Optional[str] = None,
83
87
  pre_collect: Optional[str] = None,
84
- env: Optional[Dict[str, str]] = None,
88
+ env: Optional[dict[str, str]] = None,
85
89
  verbose: str = "info",
90
+ verbose_datalad: Optional[str] = None,
86
91
  cpus: int = 1,
87
92
  mem: str = "8G",
88
93
  disk: str = "1G",
@@ -99,6 +104,7 @@ class HTCondorAdapter(QueueContextAdapter):
99
104
  self._pre_collect = pre_collect
100
105
  self._check_env(env)
101
106
  self._verbose = verbose
107
+ self._verbose_datalad = verbose_datalad
102
108
  self._cpus = cpus
103
109
  self._mem = mem
104
110
  self._disk = disk
@@ -115,7 +121,7 @@ class HTCondorAdapter(QueueContextAdapter):
115
121
  )
116
122
  self._dag_path = self._job_dir / f"{self._job_name}.dag"
117
123
 
118
- def _check_env(self, env: Optional[Dict[str, str]]) -> None:
124
+ def _check_env(self, env: Optional[dict[str, str]]) -> None:
119
125
  """Check value of env parameter on init.
120
126
 
121
127
  Parameters
@@ -201,10 +207,15 @@ class HTCondorAdapter(QueueContextAdapter):
201
207
 
202
208
  def run(self) -> str:
203
209
  """Return run commands."""
210
+ verbose_args = f"--verbose {self._verbose} "
211
+ if self._verbose_datalad is not None:
212
+ verbose_args = (
213
+ f"{verbose_args} --verbose-datalad {self._verbose_datalad} "
214
+ )
204
215
  junifer_run_args = (
205
216
  "run "
206
217
  f"{self._yaml_config_path.resolve()!s} "
207
- f"--verbose {self._verbose} "
218
+ f"{verbose_args}"
208
219
  "--element $(element)"
209
220
  )
210
221
  log_dir_prefix = (
@@ -246,10 +257,16 @@ class HTCondorAdapter(QueueContextAdapter):
246
257
 
247
258
  def collect(self) -> str:
248
259
  """Return collect commands."""
260
+ verbose_args = f"--verbose {self._verbose} "
261
+ if self._verbose_datalad is not None:
262
+ verbose_args = (
263
+ f"{verbose_args} --verbose-datalad {self._verbose_datalad} "
264
+ )
265
+
249
266
  junifer_collect_args = (
250
267
  "collect "
251
268
  f"{self._yaml_config_path.resolve()!s} "
252
- f"--verbose {self._verbose}"
269
+ f"{verbose_args}"
253
270
  )
254
271
  log_dir_prefix = f"{self._log_dir.resolve()!s}/junifer_collect"
255
272
  fixed = (
File without changes
@@ -5,7 +5,7 @@
5
5
 
6
6
  import logging
7
7
  from pathlib import Path
8
- from typing import Dict, List, Optional, Tuple, Union
8
+ from typing import Optional, Union
9
9
 
10
10
  import pytest
11
11
 
@@ -44,7 +44,7 @@ def test_GnuParallelLocalAdapter_env_shell_error() -> None:
44
44
  ],
45
45
  )
46
46
  def test_GnuParallelLocalAdapter_elements(
47
- elements: List[Union[str, Tuple]],
47
+ elements: list[Union[str, tuple]],
48
48
  expected_text: str,
49
49
  ) -> None:
50
50
  """Test GnuParallelLocalAdapter elements().
@@ -177,7 +177,7 @@ def test_GnuParallelLocalAdapter_prepare(
177
177
  tmp_path: Path,
178
178
  monkeypatch: pytest.MonkeyPatch,
179
179
  caplog: pytest.LogCaptureFixture,
180
- env: Dict[str, str],
180
+ env: dict[str, str],
181
181
  ) -> None:
182
182
  """Test GnuParallelLocalAdapter prepare().
183
183
 
@@ -5,7 +5,7 @@
5
5
 
6
6
  import logging
7
7
  from pathlib import Path
8
- from typing import Dict, List, Optional, Tuple, Union
8
+ from typing import Optional, Union
9
9
 
10
10
  import pytest
11
11
 
@@ -181,7 +181,7 @@ def test_HTCondorAdapter_run_collect(
181
181
  ],
182
182
  )
183
183
  def test_HTCondor_dag(
184
- elements: List[Union[str, Tuple]], collect: str, expected_text: str
184
+ elements: list[Union[str, tuple]], collect: str, expected_text: str
185
185
  ) -> None:
186
186
  """Test HTCondorAdapter dag().
187
187
 
@@ -218,7 +218,7 @@ def test_HTCondorAdapter_prepare(
218
218
  tmp_path: Path,
219
219
  monkeypatch: pytest.MonkeyPatch,
220
220
  caplog: pytest.LogCaptureFixture,
221
- env: Dict[str, str],
221
+ env: dict[str, str],
222
222
  ) -> None:
223
223
  """Test HTCondorAdapter prepare().
224
224
 
@@ -1,4 +1,4 @@
1
- """Provide tests for functions."""
1
+ """Provide tests for API functions."""
2
2
 
3
3
  # Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
4
4
  # Leonard Sasse <l.sasse@fz-juelich.de>
@@ -6,16 +6,19 @@
6
6
  # License: AGPL
7
7
 
8
8
  import logging
9
+ from contextlib import AbstractContextManager, nullcontext
9
10
  from pathlib import Path
10
- from typing import Dict, List, Optional, Tuple, Union
11
+ from typing import Any, Optional, Union
11
12
 
12
13
  import pytest
14
+ from nibabel.filebasedimages import ImageFileError
13
15
  from ruamel.yaml import YAML
14
16
 
15
17
  import junifer.testing.registry # noqa: F401
16
- from junifer.api.functions import collect, list_elements, queue, reset, run
18
+ from junifer.api import collect, list_elements, queue, reset, run
17
19
  from junifer.datagrabber.base import BaseDataGrabber
18
- from junifer.pipeline.registry import build
20
+ from junifer.pipeline import PipelineComponentRegistry
21
+ from junifer.typing import Elements
19
22
 
20
23
 
21
24
  # Configure YAML class
@@ -25,16 +28,41 @@ yaml.allow_unicode = True
25
28
  yaml.indent(mapping=2, sequence=4, offset=2)
26
29
 
27
30
 
31
+ # Kept for parametrizing
32
+ _datagrabber = {
33
+ "kind": "PartlyCloudyTestingDataGrabber",
34
+ }
35
+ _bids_ses_datagrabber = {
36
+ "kind": "PatternDataladDataGrabber",
37
+ "uri": "https://gin.g-node.org/juaml/datalad-example-bids-ses",
38
+ "types": ["T1w", "BOLD"],
39
+ "patterns": {
40
+ "T1w": {
41
+ "pattern": (
42
+ "{subject}/{session}/anat/{subject}_{session}_T1w.nii.gz"
43
+ ),
44
+ "space": "MNI152NLin6Asym",
45
+ },
46
+ "BOLD": {
47
+ "pattern": (
48
+ "{subject}/{session}/func/{subject}_{session}_task-rest_bold.nii.gz"
49
+ ),
50
+ "space": "MNI152NLin6Asym",
51
+ },
52
+ },
53
+ "replacements": ["subject", "session"],
54
+ "rootdir": "example_bids_ses",
55
+ }
56
+
57
+
28
58
  @pytest.fixture
29
- def datagrabber() -> Dict[str, str]:
59
+ def datagrabber() -> dict[str, str]:
30
60
  """Return a datagrabber as a dictionary."""
31
- return {
32
- "kind": "PartlyCloudyTestingDataGrabber",
33
- }
61
+ return _datagrabber.copy()
34
62
 
35
63
 
36
64
  @pytest.fixture
37
- def markers() -> List[Dict[str, str]]:
65
+ def markers() -> list[dict[str, str]]:
38
66
  """Return markers as a list of dictionary."""
39
67
  return [
40
68
  {
@@ -53,18 +81,55 @@ def markers() -> List[Dict[str, str]]:
53
81
 
54
82
 
55
83
  @pytest.fixture
56
- def storage() -> Dict[str, str]:
84
+ def storage() -> dict[str, str]:
57
85
  """Return a storage as a dictionary."""
58
86
  return {
59
87
  "kind": "SQLiteFeatureStorage",
60
88
  }
61
89
 
62
90
 
91
+ @pytest.mark.parametrize(
92
+ "datagrabber, element, expect",
93
+ [
94
+ (
95
+ _datagrabber,
96
+ [("sub-01",)],
97
+ pytest.raises(RuntimeError, match="element selectors are invalid"),
98
+ ),
99
+ (
100
+ _datagrabber,
101
+ ["sub-01"],
102
+ nullcontext(),
103
+ ),
104
+ (
105
+ _bids_ses_datagrabber,
106
+ ["sub-01"],
107
+ pytest.raises(ImageFileError, match="is not a gzip file"),
108
+ ),
109
+ (
110
+ _bids_ses_datagrabber,
111
+ [("sub-01", "ses-01")],
112
+ pytest.raises(ImageFileError, match="is not a gzip file"),
113
+ ),
114
+ (
115
+ _bids_ses_datagrabber,
116
+ [("sub-01", "ses-100")],
117
+ pytest.raises(RuntimeError, match="element selectors are invalid"),
118
+ ),
119
+ (
120
+ _bids_ses_datagrabber,
121
+ [("sub-100", "ses-01")],
122
+ pytest.raises(RuntimeError, match="element selectors are invalid"),
123
+ ),
124
+ ],
125
+ )
63
126
  def test_run_single_element(
64
127
  tmp_path: Path,
65
- datagrabber: Dict[str, str],
66
- markers: List[Dict[str, str]],
67
- storage: Dict[str, str],
128
+ datagrabber: dict[str, Any],
129
+ markers: list[dict[str, str]],
130
+ storage: dict[str, str],
131
+ element: Elements,
132
+ expect: AbstractContextManager,
68
133
  ) -> None:
69
134
  """Test run function with single element.
70
135
 
@@ -78,27 +143,32 @@ def test_run_single_element(
78
143
  Testing markers as list of dictionary.
79
144
  storage : dict
80
145
  Testing storage as dictionary.
146
+ element : list of str or tuple
147
+ The parametrized element.
148
+ expect : typing.ContextManager
149
+ The parametrized ContextManager object.
81
150
 
82
151
  """
83
152
  # Set storage
84
153
  storage["uri"] = str((tmp_path / "out.sqlite").resolve())
85
154
  # Run operations
86
- run(
87
- workdir=tmp_path,
88
- datagrabber=datagrabber,
89
- markers=markers,
90
- storage=storage,
91
- elements=["sub-01"],
92
- )
93
- # Check files
94
- files = list(tmp_path.glob("*.sqlite"))
95
- assert len(files) == 1
155
+ with expect:
156
+ run(
157
+ workdir=tmp_path,
158
+ datagrabber=datagrabber,
159
+ markers=markers,
160
+ storage=storage,
161
+ elements=element,
162
+ )
163
+ # Check files
164
+ files = list(tmp_path.glob("*.sqlite"))
165
+ assert len(files) == 1
96
166
 
97
167
 
98
168
  def test_run_single_element_with_preprocessing(
99
169
  tmp_path: Path,
100
- markers: List[Dict[str, str]],
101
- storage: Dict[str, str],
170
+ markers: list[dict[str, str]],
171
+ storage: dict[str, str],
102
172
  ) -> None:
103
173
  """Test run function with single element and pre-processing.
104
174
 
@@ -116,7 +186,7 @@ def test_run_single_element_with_preprocessing(
116
186
  storage["uri"] = str((tmp_path / "out.sqlite").resolve())
117
187
  # Run operations
118
188
  run(
119
- workdir=tmp_path,
189
+ workdir={"path": tmp_path, "cleanup": False},
120
190
  datagrabber={
121
191
  "kind": "PartlyCloudyTestingDataGrabber",
122
192
  "reduce_confounds": False,
@@ -135,11 +205,23 @@ def test_run_single_element_with_preprocessing(
135
205
  assert len(files) == 1
136
206
 
137
207
 
208
+ @pytest.mark.parametrize(
209
+ "element, expect",
210
+ [
211
+ (
212
+ [("sub-01",), ("sub-03",)],
213
+ pytest.raises(RuntimeError, match="element selectors are invalid"),
214
+ ),
215
+ (["sub-01", "sub-03"], nullcontext()),
216
+ ],
217
+ )
138
218
  def test_run_multi_element_multi_output(
139
219
  tmp_path: Path,
140
- datagrabber: Dict[str, str],
141
- markers: List[Dict[str, str]],
142
- storage: Dict[str, str],
220
+ datagrabber: dict[str, str],
221
+ markers: list[dict[str, str]],
222
+ storage: dict[str, str],
223
+ element: Elements,
224
+ expect: AbstractContextManager,
143
225
  ) -> None:
144
226
  """Test run function with multi element and multi output.
145
227
 
@@ -153,29 +235,34 @@ def test_run_multi_element_multi_output(
153
235
  Testing markers as list of dictionary.
154
236
  storage : dict
155
237
  Testing storage as dictionary.
238
+ element : list of str or tuple
239
+ The parametrized element.
240
+ expect : typing.ContextManager
241
+ The parametrized ContextManager object.
156
242
 
157
243
  """
158
244
  # Set storage
159
245
  storage["uri"] = str((tmp_path / "out.sqlite").resolve())
160
246
  storage["single_output"] = False # type: ignore
161
247
  # Run operations
162
- run(
163
- workdir=tmp_path,
164
- datagrabber=datagrabber,
165
- markers=markers,
166
- storage=storage,
167
- elements=["sub-01", "sub-03"],
168
- )
169
- # Check files
170
- files = list(tmp_path.glob("*.sqlite"))
171
- assert len(files) == 2
248
+ with expect:
249
+ run(
250
+ workdir=tmp_path,
251
+ datagrabber=datagrabber,
252
+ markers=markers,
253
+ storage=storage,
254
+ elements=element,
255
+ )
256
+ # Check files
257
+ files = list(tmp_path.glob("*.sqlite"))
258
+ assert len(files) == 2
172
259
 
173
260
 
174
261
  def test_run_multi_element_single_output(
175
262
  tmp_path: Path,
176
- datagrabber: Dict[str, str],
177
- markers: List[Dict[str, str]],
178
- storage: Dict[str, str],
263
+ datagrabber: dict[str, str],
264
+ markers: list[dict[str, str]],
265
+ storage: dict[str, str],
179
266
  ) -> None:
180
267
  """Test run function with multi element and single output.
181
268
 
@@ -210,9 +297,9 @@ def test_run_multi_element_single_output(
210
297
 
211
298
  def test_run_and_collect(
212
299
  tmp_path: Path,
213
- datagrabber: Dict[str, str],
214
- markers: List[Dict[str, str]],
215
- storage: Dict[str, str],
300
+ datagrabber: dict[str, str],
301
+ markers: list[dict[str, str]],
302
+ storage: dict[str, str],
216
303
  ) -> None:
217
304
  """Test run and collect functions.
218
305
 
@@ -240,7 +327,7 @@ def test_run_and_collect(
240
327
  storage=storage,
241
328
  )
242
329
  # Get datagrabber
243
- dg = build(
330
+ dg = PipelineComponentRegistry().build_component_instance(
244
331
  step="datagrabber", name=datagrabber["kind"], baseclass=BaseDataGrabber
245
332
  )
246
333
  elements = dg.get_elements() # type: ignore
@@ -259,9 +346,9 @@ def test_queue_correct_yaml_config(
259
346
  tmp_path: Path,
260
347
  monkeypatch: pytest.MonkeyPatch,
261
348
  caplog: pytest.LogCaptureFixture,
262
- datagrabber: Dict[str, str],
263
- markers: List[Dict[str, str]],
264
- storage: Dict[str, str],
349
+ datagrabber: dict[str, str],
350
+ markers: list[dict[str, str]],
351
+ storage: dict[str, str],
265
352
  ) -> None:
266
353
  """Test proper YAML config generation for queueing.
267
354
 
@@ -287,7 +374,10 @@ def test_queue_correct_yaml_config(
287
374
  queue(
288
375
  config={
289
376
  "with": "junifer.testing.registry",
290
- "workdir": str(tmp_path.resolve()),
377
+ "workdir": {
378
+ "path": str(tmp_path.resolve()),
379
+ "cleanup": True,
380
+ },
291
381
  "datagrabber": datagrabber,
292
382
  "markers": markers,
293
383
  "storage": storage,
@@ -342,7 +432,7 @@ def test_queue_invalid_job_queue(
342
432
  with monkeypatch.context() as m:
343
433
  m.chdir(tmp_path)
344
434
  queue(
345
- config={"elements": ["sub-001"]},
435
+ config={"elements": [("sub-001",)]},
346
436
  kind="ABC",
347
437
  )
348
438
 
@@ -366,13 +456,13 @@ def test_queue_assets_disallow_overwrite(
366
456
  m.chdir(tmp_path)
367
457
  # First generate assets
368
458
  queue(
369
- config={"elements": ["sub-001"]},
459
+ config={"elements": [("sub-001",)]},
370
460
  kind="HTCondor",
371
461
  jobname="prevent_overwrite",
372
462
  )
373
463
  # Re-run to trigger error
374
464
  queue(
375
- config={"elements": ["sub-001"]},
465
+ config={"elements": [("sub-001",)]},
376
466
  kind="HTCondor",
377
467
  jobname="prevent_overwrite",
378
468
  )
@@ -399,14 +489,14 @@ def test_queue_assets_allow_overwrite(
399
489
  m.chdir(tmp_path)
400
490
  # First generate assets
401
491
  queue(
402
- config={"elements": ["sub-001"]},
492
+ config={"elements": [("sub-001",)]},
403
493
  kind="HTCondor",
404
494
  jobname="allow_overwrite",
405
495
  )
406
496
  with caplog.at_level(logging.INFO):
407
497
  # Re-run to overwrite
408
498
  queue(
409
- config={"elements": ["sub-001"]},
499
+ config={"elements": [("sub-001",)]},
410
500
  kind="HTCondor",
411
501
  jobname="allow_overwrite",
412
502
  overwrite=True,
@@ -426,7 +516,7 @@ def test_queue_with_imports(
426
516
  tmp_path: Path,
427
517
  monkeypatch: pytest.MonkeyPatch,
428
518
  caplog: pytest.LogCaptureFixture,
429
- with_: Union[str, List[str]],
519
+ with_: Union[str, list[str]],
430
520
  ) -> None:
431
521
  """Test queue with `with` imports.
432
522
 
@@ -448,10 +538,16 @@ def test_queue_with_imports(
448
538
  (tmp_path / "a.py").touch()
449
539
  with caplog.at_level(logging.DEBUG):
450
540
  queue(
451
- config={"with": with_},
541
+ config={
542
+ "with": with_,
543
+ "workdir": {
544
+ "path": str(tmp_path.resolve()),
545
+ "cleanup": False,
546
+ },
547
+ },
452
548
  kind="HTCondor",
453
549
  jobname="with_import_check",
454
- elements="sub-001",
550
+ elements=[("sub-001",)],
455
551
  )
456
552
  assert "Copying" in caplog.text
457
553
  assert "Queue done" in caplog.text
@@ -465,10 +561,8 @@ def test_queue_with_imports(
465
561
  @pytest.mark.parametrize(
466
562
  "elements",
467
563
  [
468
- "sub-001",
469
- ["sub-001"],
470
- ["sub-001", "sub-002"],
471
- ("sub-001", "ses-001"),
564
+ [("sub-001",)],
565
+ [("sub-001",), ("sub-002",)],
472
566
  [("sub-001", "ses-001")],
473
567
  [("sub-001", "ses-001"), ("sub-001", "ses-002")],
474
568
  ],
@@ -477,7 +571,7 @@ def test_queue_with_elements(
477
571
  tmp_path: Path,
478
572
  monkeypatch: pytest.MonkeyPatch,
479
573
  caplog: pytest.LogCaptureFixture,
480
- elements: Union[str, List[Union[str, Tuple[str]]], Tuple[str]],
574
+ elements: list[tuple[str, ...]],
481
575
  ) -> None:
482
576
  """Test queue with elements.
483
577
 
@@ -489,7 +583,7 @@ def test_queue_with_elements(
489
583
  The pytest.MonkeyPatch object.
490
584
  caplog : pytest.LogCaptureFixture
491
585
  The pytest.LogCaptureFixture object.
492
- elements : str of list of str
586
+ elements : list of tuple
493
587
  The parametrized elements for the queue.
494
588
 
495
589
  """
@@ -508,7 +602,7 @@ def test_queue_without_elements(
508
602
  tmp_path: Path,
509
603
  monkeypatch: pytest.MonkeyPatch,
510
604
  caplog: pytest.LogCaptureFixture,
511
- datagrabber: Dict[str, str],
605
+ datagrabber: dict[str, str],
512
606
  ) -> None:
513
607
  """Test queue without elements.
514
608
 
@@ -536,9 +630,9 @@ def test_queue_without_elements(
536
630
 
537
631
  def test_reset_run(
538
632
  tmp_path: Path,
539
- datagrabber: Dict[str, str],
540
- markers: List[Dict[str, str]],
541
- storage: Dict[str, str],
633
+ datagrabber: dict[str, str],
634
+ markers: list[dict[str, str]],
635
+ storage: dict[str, str],
542
636
  ) -> None:
543
637
  """Test reset function for run.
544
638
 
@@ -580,9 +674,9 @@ def test_reset_run(
580
674
  def test_reset_queue(
581
675
  tmp_path: Path,
582
676
  monkeypatch: pytest.MonkeyPatch,
583
- datagrabber: Dict[str, str],
584
- markers: List[Dict[str, str]],
585
- storage: Dict[str, str],
677
+ datagrabber: dict[str, str],
678
+ markers: list[dict[str, str]],
679
+ storage: dict[str, str],
586
680
  job_name: str,
587
681
  ) -> None:
588
682
  """Test reset function for queue.
@@ -642,13 +736,13 @@ def test_reset_queue(
642
736
  @pytest.mark.parametrize(
643
737
  "elements",
644
738
  [
645
- ["sub-01"],
739
+ [("sub-01",)],
646
740
  None,
647
741
  ],
648
742
  )
649
743
  def test_list_elements(
650
- datagrabber: Dict[str, str],
651
- elements: Optional[List[str]],
744
+ datagrabber: dict[str, str],
745
+ elements: Optional[list[tuple[str, ...]]],
652
746
  ) -> None:
653
747
  """Test elements listing.
654
748