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
@@ -0,0 +1,24 @@
1
+ """Junifer CLI components."""
2
+
3
+ # Authors: Synchon Mandal <s.mandal@fz-juelich.de>
4
+ # License: AGPL
5
+
6
+ import sys
7
+
8
+ import lazy_loader as lazy
9
+
10
+
11
+ if sys.version_info < (3, 11): # pragma: no cover
12
+ from importlib_metadata import entry_points
13
+ else:
14
+ from importlib.metadata import entry_points
15
+
16
+
17
+ __getattr__, __dir__, __all__ = lazy.attach_stub(__name__, __file__)
18
+
19
+
20
+ # Register extensions
21
+ from .cli import cli
22
+
23
+ for ep in entry_points(group="junifer.ext"):
24
+ cli.add_command(ep.load(), name=ep.name)
@@ -0,0 +1,3 @@
1
+ __all__ = ["cli"]
2
+
3
+ from .cli import cli
@@ -1,4 +1,4 @@
1
- """Provide functions for cli."""
1
+ """Provide functions for CLI."""
2
2
 
3
3
  # Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
4
4
  # Synchon Mandal <s.mandal@fz-juelich.de>
@@ -8,120 +8,67 @@ import pathlib
8
8
  import subprocess
9
9
  import sys
10
10
  from pathlib import Path
11
- from typing import Dict, List, Optional, Tuple, Union
11
+ from typing import Optional, Union
12
12
 
13
13
  import click
14
- import pandas as pd
15
14
 
16
- from ..utils.logging import (
15
+ from ..api import functions as cli_func
16
+ from ..utils import (
17
17
  configure_logging,
18
- logger,
19
18
  raise_error,
20
- warn_with_log,
19
+ yaml,
21
20
  )
22
- from .functions import collect as api_collect
23
- from .functions import list_elements as api_list_elements
24
- from .functions import queue as api_queue
25
- from .functions import reset as api_reset
26
- from .functions import run as api_run
27
- from .parser import parse_yaml
21
+ from .parser import parse_elements, parse_yaml
28
22
  from .utils import (
29
23
  _get_dependency_information,
30
24
  _get_environment_information,
31
25
  _get_junifer_version,
32
26
  _get_python_information,
33
27
  _get_system_information,
34
- yaml,
35
28
  )
36
29
 
37
30
 
38
- def _parse_elements(element: Tuple[str], config: Dict) -> Union[List, None]:
39
- """Parse elements from cli.
31
+ __all__ = [
32
+ "afni_docker",
33
+ "ants_docker",
34
+ "cli",
35
+ "collect",
36
+ "freesurfer_docker",
37
+ "fsl_docker",
38
+ "list_elements",
39
+ "queue",
40
+ "reset",
41
+ "run",
42
+ "selftest",
43
+ "setup",
44
+ "wtf",
45
+ ]
46
+
47
+
48
+ def _validate_optional_verbose(
49
+ ctx: click.Context, param: str, value: Optional[str]
50
+ ):
51
+ """Validate optional verbose option.
40
52
 
41
53
  Parameters
42
54
  ----------
43
- element : tuple of str
44
- The element(s) to operate on.
45
- config : dict
46
- The configuration to operate using.
55
+ ctx : click.Context
56
+ The context of the command.
57
+ param : str
58
+ The parameter to validate.
59
+ value : str
60
+ The value to validate.
47
61
 
48
62
  Returns
49
63
  -------
50
- list or None
51
- The element(s) as list or None.
52
-
53
- Raises
54
- ------
55
- ValueError
56
- If no element is found either in the command-line options or
57
- the configuration file.
58
-
59
- Warns
60
- -----
61
- RuntimeWarning
62
- If elements are specified both via the command-line options and
63
- the configuration file.
64
+ str or int or None
65
+ The validated value.
64
66
 
65
67
  """
66
- logger.debug(f"Parsing elements: {element}")
67
- # Early return None to continue with all elements
68
- if len(element) == 0:
69
- return None
70
- # Check if the element is a file for single element;
71
- # if yes, then parse elements from it
72
- if len(element) == 1 and Path(element[0]).resolve().is_file():
73
- elements = _parse_elements_file(Path(element[0]).resolve())
68
+ if value is None:
69
+ return value
74
70
  else:
75
- # Process multi-keyed elements
76
- elements = [tuple(x.split(",")) if "," in x else x for x in element]
77
- logger.debug(f"Parsed elements: {elements}")
78
- if elements is not None and "elements" in config:
79
- warn_with_log(
80
- "One or more elements have been specified in both the command "
81
- "line and in the config file. The command line has precedence "
82
- "over the configuration file. That is, the elements specified "
83
- "in the command line will be used. The elements specified in "
84
- "the configuration file will be ignored. To remove this warning, "
85
- "please remove the `elements` item from the configuration file."
86
- )
87
- elif elements is None:
88
- # Check in config
89
- elements = config.get("elements", None)
90
- if elements is None:
91
- raise_error(
92
- "The `elements` key is set in the configuration, but its value"
93
- " is `None`. It is likely that there is an empty `elements` "
94
- "section in the yaml configuration file."
95
- )
96
- return elements
97
-
98
-
99
- def _parse_elements_file(filepath: Path) -> List[Tuple[str, ...]]:
100
- """Parse elements from file.
101
-
102
- Parameters
103
- ----------
104
- filepath : pathlib.Path
105
- The path to the element file.
106
-
107
- Returns
108
- -------
109
- list of tuple of str
110
- The element(s) as list.
111
-
112
- """
113
- # Read CSV into dataframe
114
- csv_df = pd.read_csv(
115
- filepath,
116
- header=None, # no header # type: ignore
117
- index_col=False, # no index column
118
- dtype=str,
119
- skipinitialspace=True, # no leading space after delimiter
120
- )
121
- # Remove trailing whitespace in cell entries
122
- csv_df_trimmed = csv_df.apply(lambda x: x.str.strip())
123
- # Convert to list of tuple of str
124
- return list(map(tuple, csv_df_trimmed.to_numpy()))
71
+ return _validate_verbose(ctx, param, value)
125
72
 
126
73
 
127
74
  def _validate_verbose(
@@ -164,9 +111,11 @@ def _validate_verbose(
164
111
  )
165
112
 
166
113
 
167
- @click.group()
114
+ @click.group
115
+ @click.version_option()
116
+ @click.help_option()
168
117
  def cli() -> None: # pragma: no cover
169
- """CLI for JUelich NeuroImaging FEature extractoR."""
118
+ """JUelich NeuroImaging FEature extractoR."""
170
119
 
171
120
 
172
121
  @cli.command()
@@ -184,10 +133,19 @@ def cli() -> None: # pragma: no cover
184
133
  callback=_validate_verbose,
185
134
  default="info",
186
135
  )
136
+ @click.option(
137
+ "--verbose-datalad",
138
+ type=click.UNPROCESSED,
139
+ callback=_validate_optional_verbose,
140
+ default=None,
141
+ )
187
142
  def run(
188
- filepath: click.Path, element: Tuple[str], verbose: Union[str, int]
143
+ filepath: click.Path,
144
+ element: tuple[str],
145
+ verbose: Union[str, int],
146
+ verbose_datalad: Optional[Union[str, int]],
189
147
  ) -> None:
190
- """Run command for CLI.
148
+ """Run feature extraction.
191
149
 
192
150
  \f
193
151
 
@@ -196,15 +154,18 @@ def run(
196
154
  filepath : click.Path
197
155
  The filepath to the configuration file.
198
156
  element : tuple of str
199
- The element to operate on.
157
+ The element(s) to operate on.
200
158
  verbose : click.Choice
201
159
  The verbosity level: warning, info or debug (default "info").
160
+ verbose_datalad : click.Choice or None
161
+ The verbosity level for datalad: warning, info or debug (default None).
202
162
 
203
163
  """
204
- configure_logging(level=verbose)
164
+ # Setup logging
165
+ configure_logging(level=verbose, level_datalad=verbose_datalad)
205
166
  # TODO(synchon): add validation
206
167
  # Parse YAML
207
- config = parse_yaml(filepath) # type: ignore
168
+ config = parse_yaml(filepath)
208
169
  # Retrieve working directory
209
170
  workdir = config["workdir"]
210
171
  # Fetch datagrabber
@@ -219,9 +180,9 @@ def run(
219
180
  if preprocessors is not None and not isinstance(preprocessors, list):
220
181
  preprocessors = [preprocessors]
221
182
  # Parse elements
222
- elements = _parse_elements(element, config)
183
+ elements = parse_elements(element, config)
223
184
  # Perform operation
224
- api_run(
185
+ cli_func.run(
225
186
  workdir=workdir,
226
187
  datagrabber=datagrabber,
227
188
  markers=markers,
@@ -245,8 +206,18 @@ def run(
245
206
  callback=_validate_verbose,
246
207
  default="info",
247
208
  )
248
- def collect(filepath: click.Path, verbose: Union[str, int]) -> None:
249
- """Collect command for CLI.
209
+ @click.option(
210
+ "--verbose-datalad",
211
+ type=click.UNPROCESSED,
212
+ callback=_validate_optional_verbose,
213
+ default=None,
214
+ )
215
+ def collect(
216
+ filepath: click.Path,
217
+ verbose: Union[str, int],
218
+ verbose_datalad: Union[str, int, None],
219
+ ) -> None:
220
+ """Collect extracted features.
250
221
 
251
222
  \f
252
223
 
@@ -256,14 +227,19 @@ def collect(filepath: click.Path, verbose: Union[str, int]) -> None:
256
227
  The filepath to the configuration file.
257
228
  verbose : click.Choice
258
229
  The verbosity level: warning, info or debug (default "info").
230
+ verbose_datalad : click.Choice or None
231
+ The verbosity level for datalad: warning, info or debug (default None).
259
232
 
260
233
  """
261
- configure_logging(level=verbose)
234
+ # Setup logging
235
+ configure_logging(level=verbose, level_datalad=verbose_datalad)
262
236
  # TODO: add validation
263
- config = parse_yaml(filepath) # type: ignore
237
+ # Parse YAML
238
+ config = parse_yaml(filepath)
239
+ # Fetch storage
264
240
  storage = config["storage"]
265
241
  # Perform operation
266
- api_collect(storage=storage)
242
+ cli_func.collect(storage=storage)
267
243
 
268
244
 
269
245
  @cli.command()
@@ -283,14 +259,21 @@ def collect(filepath: click.Path, verbose: Union[str, int]) -> None:
283
259
  callback=_validate_verbose,
284
260
  default="info",
285
261
  )
262
+ @click.option(
263
+ "--verbose-datalad",
264
+ type=click.UNPROCESSED,
265
+ callback=_validate_optional_verbose,
266
+ default=None,
267
+ )
286
268
  def queue(
287
269
  filepath: click.Path,
288
- element: str,
270
+ element: tuple[str],
289
271
  overwrite: bool,
290
272
  submit: bool,
291
273
  verbose: Union[str, int],
274
+ verbose_datalad: Union[str, int, None],
292
275
  ) -> None:
293
- """Queue command for CLI.
276
+ """Queue feature extraction.
294
277
 
295
278
  \f
296
279
 
@@ -298,25 +281,38 @@ def queue(
298
281
  ----------
299
282
  filepath : click.Path
300
283
  The filepath to the configuration file.
301
- element : str
302
- The element to operate using.
284
+ element : tuple of str
285
+ The element(s) to operate on.
303
286
  overwrite : bool
304
287
  Whether to overwrite existing directory.
305
288
  submit : bool
306
289
  Whether to submit the job.
307
290
  verbose : click.Choice
308
291
  The verbosity level: warning, info or debug (default "info").
292
+ verbose_datalad : click.Choice or None
293
+ The verbosity level for datalad: warning, info or debug (default None).
294
+
295
+ Raises
296
+ ------
297
+ ValueError
298
+ If no ``queue`` section is found in the YAML.
309
299
 
310
300
  """
311
- configure_logging(level=verbose)
301
+ # Setup logging
302
+ configure_logging(level=verbose, level_datalad=verbose_datalad)
312
303
  # TODO: add validation
304
+ # Parse YAML
313
305
  config = parse_yaml(filepath) # type: ignore
314
- elements = _parse_elements(element, config)
306
+ # Check queue section
315
307
  if "queue" not in config:
316
308
  raise_error(f"No queue configuration found in {filepath}.")
309
+ # Parse elements
310
+ elements = parse_elements(element, config)
311
+ # Separate out queue section
317
312
  queue_config = config.pop("queue")
318
313
  kind = queue_config.pop("kind")
319
- api_queue(
314
+ # Perform operation
315
+ cli_func.queue(
320
316
  config=config,
321
317
  kind=kind,
322
318
  overwrite=overwrite,
@@ -329,7 +325,7 @@ def queue(
329
325
  @cli.command()
330
326
  @click.option("--long", "long_", is_flag=True)
331
327
  def wtf(long_: bool) -> None:
332
- """Wtf command for CLI.
328
+ """WTF?!.
333
329
 
334
330
  \f
335
331
 
@@ -352,7 +348,7 @@ def wtf(long_: bool) -> None:
352
348
  @cli.command()
353
349
  @click.argument("subpkg", type=str)
354
350
  def selftest(subpkg: str) -> None:
355
- """Selftest command for CLI.
351
+ """Selftest.
356
352
 
357
353
  \f
358
354
 
@@ -429,11 +425,18 @@ def selftest(subpkg: str) -> None:
429
425
  callback=_validate_verbose,
430
426
  default="info",
431
427
  )
428
+ @click.option(
429
+ "--verbose-datalad",
430
+ type=click.UNPROCESSED,
431
+ callback=_validate_optional_verbose,
432
+ default=None,
433
+ )
432
434
  def reset(
433
435
  filepath: click.Path,
434
436
  verbose: Union[str, int],
437
+ verbose_datalad: Union[str, int, None],
435
438
  ) -> None:
436
- """Reset command for CLI.
439
+ """Reset generated assets.
437
440
 
438
441
  \f
439
442
 
@@ -443,13 +446,16 @@ def reset(
443
446
  The filepath to the configuration file.
444
447
  verbose : click.Choice
445
448
  The verbosity level: warning, info or debug (default "info").
449
+ verbose_datalad : click.Choice or None
450
+ The verbosity level for datalad: warning, info or debug (default None).
446
451
 
447
452
  """
448
- configure_logging(level=verbose)
453
+ # Setup logging
454
+ configure_logging(level=verbose, level_datalad=verbose_datalad)
449
455
  # Parse YAML
450
456
  config = parse_yaml(filepath)
451
457
  # Perform operation
452
- api_reset(config)
458
+ cli_func.reset(config)
453
459
 
454
460
 
455
461
  @cli.command()
@@ -472,13 +478,20 @@ def reset(
472
478
  callback=_validate_verbose,
473
479
  default="info",
474
480
  )
481
+ @click.option(
482
+ "--verbose-datalad",
483
+ type=click.UNPROCESSED,
484
+ callback=_validate_optional_verbose,
485
+ default=None,
486
+ )
475
487
  def list_elements(
476
488
  filepath: click.Path,
477
- element: Tuple[str],
489
+ element: tuple[str],
478
490
  output_file: Optional[click.Path],
479
491
  verbose: Union[str, int],
492
+ verbose_datalad: Union[str, int, None],
480
493
  ) -> None:
481
- """Element listing command for CLI.
494
+ """List elements of a dataset.
482
495
 
483
496
  \f
484
497
 
@@ -487,23 +500,26 @@ def list_elements(
487
500
  filepath : click.Path
488
501
  The filepath to the configuration file.
489
502
  element : tuple of str
490
- The element to operate on.
503
+ The element(s) to operate on.
491
504
  output_file : click.Path or None
492
505
  The path to write the output to. If not None, writing to
493
506
  stdout is not performed.
494
507
  verbose : click.Choice
495
508
  The verbosity level: warning, info or debug (default "info").
509
+ verbose_datalad : click.Choice or None
510
+ The verbosity level for datalad: warning, info or debug (default None
496
511
 
497
512
  """
498
- configure_logging(level=verbose)
513
+ # Setup logging
514
+ configure_logging(level=verbose, level_datalad=verbose_datalad)
499
515
  # Parse YAML
500
- config = parse_yaml(filepath) # type: ignore
516
+ config = parse_yaml(filepath)
501
517
  # Fetch datagrabber
502
518
  datagrabber = config["datagrabber"]
503
519
  # Parse elements
504
- elements = _parse_elements(element, config)
520
+ elements = parse_elements(element, config)
505
521
  # Perform operation
506
- listed_elements = api_list_elements(
522
+ listed_elements = cli_func.list_elements(
507
523
  datagrabber=datagrabber,
508
524
  elements=elements,
509
525
  )
@@ -517,7 +533,7 @@ def list_elements(
517
533
 
518
534
  @cli.group()
519
535
  def setup() -> None: # pragma: no cover
520
- """Configure commands for Junifer."""
536
+ """Configure external tools."""
521
537
  pass
522
538
 
523
539