junifer 0.0.7.dev332__py3-none-any.whl → 0.0.8__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (293) hide show
  1. junifer/_version.py +9 -19
  2. junifer/api/__init__.pyi +17 -2
  3. junifer/api/functions.py +222 -39
  4. junifer/api/queue_context/__init__.pyi +11 -3
  5. junifer/api/queue_context/gnu_parallel_local_adapter.py +81 -120
  6. junifer/api/queue_context/htcondor_adapter.py +118 -181
  7. junifer/api/queue_context/queue_context_adapter.py +51 -7
  8. junifer/api/queue_context/tests/test_gnu_parallel_local_adapter.py +10 -35
  9. junifer/api/queue_context/tests/test_htcondor_adapter.py +13 -50
  10. junifer/api/res/fsl/run_fsl_docker.sh +4 -0
  11. junifer/api/tests/test_functions.py +863 -36
  12. junifer/cli/__init__.py +1 -7
  13. junifer/cli/cli.py +41 -22
  14. junifer/cli/parser.py +23 -147
  15. junifer/cli/tests/data/gmd_mean.yaml +6 -6
  16. junifer/cli/tests/data/gmd_mean_htcondor.yaml +6 -5
  17. junifer/cli/tests/data/partly_cloudy_agg_mean_tian.yml +1 -0
  18. junifer/cli/tests/test_cli.py +120 -4
  19. junifer/cli/tests/test_cli_utils.py +23 -6
  20. junifer/cli/utils.py +14 -9
  21. junifer/configs/__init__.py +5 -0
  22. junifer/configs/__init__.pyi +0 -0
  23. junifer/configs/juseless/datagrabbers/__init__.pyi +4 -2
  24. junifer/configs/juseless/datagrabbers/aomic_id1000_vbm.py +18 -24
  25. junifer/configs/juseless/datagrabbers/camcan_vbm.py +20 -27
  26. junifer/configs/juseless/datagrabbers/ixi_vbm.py +44 -52
  27. junifer/configs/juseless/datagrabbers/tests/test_ixi_vbm.py +0 -7
  28. junifer/configs/juseless/datagrabbers/tests/test_ucla.py +2 -19
  29. junifer/configs/juseless/datagrabbers/ucla.py +111 -104
  30. junifer/configs/juseless/datagrabbers/ukb_vbm.py +19 -25
  31. junifer/configs/py.typed +0 -0
  32. junifer/conftest.py +63 -24
  33. junifer/data/_dispatch.py +9 -19
  34. junifer/data/coordinates/_ants_coordinates_warper.py +4 -1
  35. junifer/data/coordinates/_coordinates.py +51 -6
  36. junifer/data/coordinates/_fsl_coordinates_warper.py +4 -1
  37. junifer/data/coordinates/tests/test_coordinates.py +15 -3
  38. junifer/data/coordinates/tests/test_coordinates_names.py +37 -0
  39. junifer/data/maps/_ants_maps_warper.py +18 -12
  40. junifer/data/maps/_fsl_maps_warper.py +7 -3
  41. junifer/data/maps/_maps.py +12 -8
  42. junifer/data/maps/tests/test_maps.py +13 -21
  43. junifer/data/masks/_ants_mask_warper.py +18 -12
  44. junifer/data/masks/_fsl_mask_warper.py +7 -3
  45. junifer/data/masks/_masks.py +15 -12
  46. junifer/data/masks/tests/test_masks.py +20 -17
  47. junifer/data/parcellations/_ants_parcellation_warper.py +18 -12
  48. junifer/data/parcellations/_fsl_parcellation_warper.py +7 -5
  49. junifer/data/parcellations/_parcellations.py +125 -91
  50. junifer/data/parcellations/tests/test_parcellations.py +122 -1
  51. junifer/data/template_spaces.py +117 -50
  52. junifer/data/tests/test_template_spaces.py +10 -7
  53. junifer/data/utils.py +10 -8
  54. junifer/datagrabber/__init__.pyi +38 -5
  55. junifer/datagrabber/aomic/__init__.pyi +8 -1
  56. junifer/datagrabber/aomic/_types.py +22 -0
  57. junifer/datagrabber/aomic/id1000.py +193 -183
  58. junifer/datagrabber/aomic/piop1.py +215 -259
  59. junifer/datagrabber/aomic/piop2.py +211 -244
  60. junifer/datagrabber/aomic/tests/test_id1000.py +70 -53
  61. junifer/datagrabber/aomic/tests/test_piop1.py +98 -102
  62. junifer/datagrabber/aomic/tests/test_piop2.py +88 -85
  63. junifer/datagrabber/base.py +253 -79
  64. junifer/datagrabber/datalad_base.py +127 -76
  65. junifer/datagrabber/dmcc13_benchmark.py +204 -289
  66. junifer/datagrabber/hcp1200/__init__.pyi +7 -2
  67. junifer/datagrabber/hcp1200/datalad_hcp1200.py +61 -40
  68. junifer/datagrabber/hcp1200/hcp1200.py +151 -164
  69. junifer/datagrabber/hcp1200/tests/test_hcp1200.py +116 -128
  70. junifer/datagrabber/multiple.py +183 -63
  71. junifer/datagrabber/pattern.py +358 -227
  72. junifer/datagrabber/pattern_datalad.py +84 -124
  73. junifer/datagrabber/pattern_validation_mixin.py +22 -50
  74. junifer/datagrabber/tests/test_base.py +17 -4
  75. junifer/datagrabber/tests/test_datalad_base.py +20 -27
  76. junifer/datagrabber/tests/test_dmcc13_benchmark.py +110 -122
  77. junifer/datagrabber/tests/test_multiple.py +293 -31
  78. junifer/datagrabber/tests/test_pattern.py +577 -18
  79. junifer/datagrabber/tests/test_pattern_datalad.py +177 -107
  80. junifer/datagrabber/tests/test_pattern_validation_mixin.py +9 -51
  81. junifer/datareader/default.py +8 -5
  82. junifer/datareader/tests/test_default_reader.py +1 -1
  83. junifer/external/BrainPrint/.codecov.yml +2 -0
  84. junifer/external/BrainPrint/.codespellignore +2 -0
  85. junifer/external/BrainPrint/.github/ISSUE_TEMPLATE/bug-report.md +45 -0
  86. junifer/external/BrainPrint/.github/ISSUE_TEMPLATE/documentation.md +12 -0
  87. junifer/external/BrainPrint/.github/ISSUE_TEMPLATE/feature-request.md +24 -0
  88. junifer/external/BrainPrint/.github/ISSUE_TEMPLATE/questions-help-support.md +28 -0
  89. junifer/external/BrainPrint/.github/dependabot.yml +6 -0
  90. junifer/external/BrainPrint/.github/workflows/build.yml +53 -0
  91. junifer/external/BrainPrint/.github/workflows/code-style.yml +44 -0
  92. junifer/external/BrainPrint/.github/workflows/doc.yml +65 -0
  93. junifer/external/BrainPrint/.github/workflows/publish.yml +31 -0
  94. junifer/external/BrainPrint/.github/workflows/pytest.yml +54 -0
  95. junifer/external/BrainPrint/.gitignore +123 -0
  96. junifer/external/BrainPrint/LICENSE +21 -0
  97. junifer/external/BrainPrint/README.md +108 -0
  98. junifer/external/BrainPrint/brainprint/cli/__init__.py +11 -0
  99. junifer/external/BrainPrint/brainprint/cli/help_text.py +169 -0
  100. junifer/external/BrainPrint/brainprint/cli/parser.py +150 -0
  101. junifer/external/BrainPrint/brainprint/cli/utils.py +14 -0
  102. junifer/external/BrainPrint/brainprint/commands/__init__.py +0 -0
  103. junifer/external/BrainPrint/brainprint/commands/sys_info.py +18 -0
  104. junifer/external/BrainPrint/brainprint/utils/tests/__init__.py +0 -0
  105. junifer/external/BrainPrint/brainprint/utils/tests/test_config.py +33 -0
  106. junifer/external/BrainPrint/doc/Makefile +20 -0
  107. junifer/external/BrainPrint/doc/_static/.gitkeep +0 -0
  108. junifer/external/BrainPrint/doc/_templates/autosummary/class.rst +10 -0
  109. junifer/external/BrainPrint/doc/_templates/autosummary/function.rst +8 -0
  110. junifer/external/BrainPrint/doc/_templates/autosummary/module.rst +6 -0
  111. junifer/external/BrainPrint/doc/api/index.rst +11 -0
  112. junifer/external/BrainPrint/doc/conf.py +272 -0
  113. junifer/external/BrainPrint/doc/index.rst +140 -0
  114. junifer/external/BrainPrint/doc/links.inc +36 -0
  115. junifer/external/BrainPrint/doc/make.bat +35 -0
  116. junifer/external/BrainPrint/doc/references.bib +23 -0
  117. junifer/external/BrainPrint/pyproject.toml +170 -0
  118. junifer/external/BrainPrint/setup.py +3 -0
  119. junifer/external/__init__.py +5 -0
  120. junifer/external/__init__.pyi +0 -0
  121. junifer/external/nilearn/junifer_connectivity_measure.py +95 -39
  122. junifer/external/nilearn/junifer_nifti_spheres_masker.py +226 -67
  123. junifer/external/nilearn/tests/test_junifer_connectivity_measure.py +39 -27
  124. junifer/external/nilearn/tests/test_junifer_nifti_spheres_masker.py +231 -21
  125. junifer/external/py.typed +0 -0
  126. junifer/markers/__init__.pyi +6 -3
  127. junifer/markers/base.py +126 -76
  128. junifer/markers/brainprint.py +30 -39
  129. junifer/markers/complexity/__init__.py +20 -3
  130. junifer/markers/complexity/complexity_base.py +40 -41
  131. junifer/markers/complexity/hurst_exponent.py +22 -35
  132. junifer/markers/complexity/multiscale_entropy_auc.py +53 -41
  133. junifer/markers/complexity/perm_entropy.py +22 -36
  134. junifer/markers/complexity/range_entropy.py +22 -35
  135. junifer/markers/complexity/range_entropy_auc.py +27 -36
  136. junifer/markers/complexity/sample_entropy.py +22 -36
  137. junifer/markers/complexity/tests/test_complexity_registry.py +48 -0
  138. junifer/markers/complexity/tests/test_hurst_exponent.py +47 -36
  139. junifer/markers/complexity/tests/test_multiscale_entropy_auc.py +50 -36
  140. junifer/markers/complexity/tests/test_perm_entropy.py +48 -36
  141. junifer/markers/complexity/tests/test_range_entropy.py +47 -36
  142. junifer/markers/complexity/tests/test_range_entropy_auc.py +47 -36
  143. junifer/markers/complexity/tests/test_sample_entropy.py +48 -36
  144. junifer/markers/complexity/tests/test_weighted_perm_entropy.py +50 -36
  145. junifer/markers/complexity/weighted_perm_entropy.py +22 -36
  146. junifer/markers/ets_rss.py +35 -31
  147. junifer/markers/falff/__init__.pyi +7 -1
  148. junifer/markers/falff/_afni_falff.py +22 -9
  149. junifer/markers/falff/_junifer_falff.py +47 -31
  150. junifer/markers/falff/falff_base.py +80 -60
  151. junifer/markers/falff/falff_maps.py +17 -41
  152. junifer/markers/falff/falff_parcels.py +26 -51
  153. junifer/markers/falff/falff_spheres.py +34 -61
  154. junifer/markers/falff/tests/test_falff_maps.py +20 -23
  155. junifer/markers/falff/tests/test_falff_mask.py +99 -0
  156. junifer/markers/falff/tests/test_falff_parcels.py +14 -10
  157. junifer/markers/falff/tests/test_falff_spheres.py +14 -10
  158. junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +32 -34
  159. junifer/markers/functional_connectivity/edge_functional_connectivity_maps.py +12 -25
  160. junifer/markers/functional_connectivity/edge_functional_connectivity_parcels.py +19 -34
  161. junifer/markers/functional_connectivity/edge_functional_connectivity_spheres.py +24 -44
  162. junifer/markers/functional_connectivity/functional_connectivity_base.py +50 -40
  163. junifer/markers/functional_connectivity/functional_connectivity_maps.py +12 -25
  164. junifer/markers/functional_connectivity/functional_connectivity_parcels.py +19 -34
  165. junifer/markers/functional_connectivity/functional_connectivity_spheres.py +24 -45
  166. junifer/markers/functional_connectivity/tests/test_crossparcellation_functional_connectivity.py +21 -22
  167. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_maps.py +8 -7
  168. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_parcels.py +8 -4
  169. junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_spheres.py +8 -4
  170. junifer/markers/functional_connectivity/tests/test_functional_connectivity_maps.py +8 -7
  171. junifer/markers/functional_connectivity/tests/test_functional_connectivity_parcels.py +9 -5
  172. junifer/markers/functional_connectivity/tests/test_functional_connectivity_spheres.py +8 -12
  173. junifer/markers/maps_aggregation.py +77 -55
  174. junifer/markers/parcel_aggregation.py +91 -70
  175. junifer/markers/reho/__init__.pyi +7 -1
  176. junifer/markers/reho/_afni_reho.py +23 -14
  177. junifer/markers/reho/_junifer_reho.py +112 -123
  178. junifer/markers/reho/reho_base.py +115 -37
  179. junifer/markers/reho/reho_maps.py +18 -32
  180. junifer/markers/reho/reho_parcels.py +26 -41
  181. junifer/markers/reho/reho_spheres.py +33 -54
  182. junifer/markers/reho/tests/test_junifer_reho.py +178 -0
  183. junifer/markers/reho/tests/test_reho_maps.py +27 -25
  184. junifer/markers/reho/tests/test_reho_parcels.py +28 -22
  185. junifer/markers/reho/tests/test_reho_spheres.py +16 -12
  186. junifer/markers/sphere_aggregation.py +88 -72
  187. junifer/markers/temporal_snr/temporal_snr_base.py +32 -30
  188. junifer/markers/temporal_snr/temporal_snr_maps.py +9 -18
  189. junifer/markers/temporal_snr/temporal_snr_parcels.py +19 -27
  190. junifer/markers/temporal_snr/temporal_snr_spheres.py +27 -41
  191. junifer/markers/temporal_snr/tests/test_temporal_snr_base.py +2 -2
  192. junifer/markers/temporal_snr/tests/test_temporal_snr_maps.py +17 -22
  193. junifer/markers/temporal_snr/tests/test_temporal_snr_parcels.py +11 -3
  194. junifer/markers/temporal_snr/tests/test_temporal_snr_spheres.py +9 -9
  195. junifer/markers/tests/test_brainprint.py +10 -9
  196. junifer/markers/tests/test_ets_rss.py +7 -3
  197. junifer/markers/tests/test_lost_regions.py +279 -0
  198. junifer/markers/tests/test_maps_aggregation.py +67 -114
  199. junifer/markers/tests/test_marker_utils.py +40 -1
  200. junifer/markers/tests/test_markers_base.py +275 -6
  201. junifer/markers/tests/test_parcel_aggregation.py +91 -53
  202. junifer/markers/tests/test_sphere_aggregation.py +53 -47
  203. junifer/markers/utils.py +267 -5
  204. junifer/onthefly/__init__.py +2 -3
  205. junifer/onthefly/__init__.pyi +4 -0
  206. junifer/onthefly/_brainprint.py +3 -5
  207. junifer/onthefly/py.typed +0 -0
  208. junifer/onthefly/read_transform.py +11 -9
  209. junifer/onthefly/tests/test_read_transform.py +7 -7
  210. junifer/pipeline/__init__.pyi +4 -2
  211. junifer/pipeline/marker_collection.py +14 -10
  212. junifer/pipeline/pipeline_component_registry.py +25 -6
  213. junifer/pipeline/pipeline_step_mixin.py +5 -12
  214. junifer/pipeline/tests/test_data_object_dumper.py +10 -10
  215. junifer/pipeline/tests/test_marker_collection.py +145 -168
  216. junifer/pipeline/tests/test_pipeline_component_registry.py +52 -8
  217. junifer/pipeline/tests/test_pipeline_step_mixin.py +12 -26
  218. junifer/pipeline/tests/test_update_meta_mixin.py +4 -5
  219. junifer/pipeline/tests/test_workdir_manager.py +39 -0
  220. junifer/pipeline/update_meta_mixin.py +13 -10
  221. junifer/pipeline/utils.py +22 -17
  222. junifer/pipeline/workdir_manager.py +41 -32
  223. junifer/preprocess/__init__.pyi +9 -4
  224. junifer/preprocess/_temporal_filter.py +34 -33
  225. junifer/preprocess/_temporal_slicer.py +17 -30
  226. junifer/preprocess/base.py +99 -55
  227. junifer/preprocess/confounds/__init__.pyi +10 -2
  228. junifer/preprocess/confounds/fmriprep_confound_remover.py +87 -109
  229. junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py +64 -45
  230. junifer/preprocess/smoothing/__init__.pyi +2 -2
  231. junifer/preprocess/smoothing/_afni_smoothing.py +8 -7
  232. junifer/preprocess/smoothing/_fsl_smoothing.py +6 -4
  233. junifer/preprocess/smoothing/_nilearn_smoothing.py +7 -5
  234. junifer/preprocess/smoothing/smoothing.py +59 -40
  235. junifer/preprocess/smoothing/tests/test_smoothing.py +28 -8
  236. junifer/preprocess/tests/test_preprocess_base.py +17 -9
  237. junifer/preprocess/tests/test_temporal_filter.py +37 -16
  238. junifer/preprocess/tests/test_temporal_slicer.py +12 -12
  239. junifer/preprocess/warping/__init__.pyi +2 -2
  240. junifer/preprocess/warping/_ants_warper.py +56 -40
  241. junifer/preprocess/warping/_fsl_warper.py +49 -36
  242. junifer/preprocess/warping/_utils.py +106 -0
  243. junifer/preprocess/warping/space_warper.py +99 -98
  244. junifer/preprocess/warping/tests/test_space_warper.py +46 -41
  245. junifer/preprocess/warping/tests/test_warping_utils.py +163 -0
  246. junifer/stats.py +46 -34
  247. junifer/storage/__init__.pyi +8 -4
  248. junifer/storage/base.py +129 -64
  249. junifer/storage/hdf5.py +307 -199
  250. junifer/storage/pandas_base.py +46 -24
  251. junifer/storage/sqlite.py +99 -62
  252. junifer/storage/tests/data/collected_h5io_fork.hdf5 +0 -0
  253. junifer/storage/tests/test_hdf5.py +147 -12
  254. junifer/storage/tests/test_repeated_storage.py +293 -0
  255. junifer/storage/tests/test_sqlite.py +9 -20
  256. junifer/storage/tests/test_storage_base.py +18 -21
  257. junifer/storage/tests/test_utils.py +83 -22
  258. junifer/storage/utils.py +58 -38
  259. junifer/testing/__init__.pyi +2 -2
  260. junifer/testing/datagrabbers.py +480 -44
  261. junifer/testing/registry.py +12 -0
  262. junifer/testing/tests/test_adhdtesting_datagrabber.py +24 -0
  263. junifer/testing/tests/test_oasisvmbtesting_datagrabber.py +5 -0
  264. junifer/testing/tests/test_partlycloudytesting_datagrabber.py +52 -0
  265. junifer/testing/tests/test_spmauditory_datagrabber.py +16 -0
  266. junifer/testing/tests/test_testing_registry.py +31 -0
  267. junifer/testing/tests/test_testing_utils.py +35 -0
  268. junifer/testing/tests/test_uclacnpvbmtesting_datagrabber.py +81 -0
  269. junifer/testing/utils.py +33 -1
  270. junifer/tests/test_stats.py +1 -5
  271. junifer/typing/__init__.pyi +2 -0
  272. junifer/typing/_typing.py +34 -19
  273. junifer/typing/py.typed +0 -0
  274. junifer/utils/__init__.pyi +10 -1
  275. junifer/utils/_config.py +1 -2
  276. junifer/utils/helpers.py +68 -2
  277. junifer/utils/logging.py +31 -7
  278. junifer/utils/tests/test_helpers.py +36 -1
  279. {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/METADATA +43 -35
  280. junifer-0.0.8.dist-info/RECORD +402 -0
  281. {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/WHEEL +1 -1
  282. junifer/cli/tests/test_parser.py +0 -280
  283. junifer/external/h5io/h5io/__init__.py +0 -15
  284. junifer/external/h5io/h5io/_h5io.py +0 -767
  285. junifer/external/h5io/h5io/_version.py +0 -1
  286. junifer/external/h5io/h5io/chunked_array.py +0 -94
  287. junifer/external/h5io/h5io/chunked_list.py +0 -65
  288. junifer/markers/complexity/__init__.pyi +0 -17
  289. junifer-0.0.7.dev332.dist-info/RECORD +0 -353
  290. {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/entry_points.txt +0 -0
  291. {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/licenses/AUTHORS.rst +0 -0
  292. {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/licenses/LICENSE.md +0 -0
  293. {junifer-0.0.7.dev332.dist-info → junifer-0.0.8.dist-info}/top_level.txt +0 -0
junifer/_version.py CHANGED
@@ -1,5 +1,6 @@
1
- # file generated by setuptools-scm
1
+ # file generated by vcs-versioning
2
2
  # don't change, don't track in version control
3
+ from __future__ import annotations
3
4
 
4
5
  __all__ = [
5
6
  "__version__",
@@ -10,25 +11,14 @@ __all__ = [
10
11
  "commit_id",
11
12
  ]
12
13
 
13
- TYPE_CHECKING = False
14
- if TYPE_CHECKING:
15
- from typing import Tuple
16
- from typing import Union
17
-
18
- VERSION_TUPLE = Tuple[Union[int, str], ...]
19
- COMMIT_ID = Union[str, None]
20
- else:
21
- VERSION_TUPLE = object
22
- COMMIT_ID = object
23
-
24
14
  version: str
25
15
  __version__: str
26
- __version_tuple__: VERSION_TUPLE
27
- version_tuple: VERSION_TUPLE
28
- commit_id: COMMIT_ID
29
- __commit_id__: COMMIT_ID
16
+ __version_tuple__: tuple[int | str, ...]
17
+ version_tuple: tuple[int | str, ...]
18
+ commit_id: str | None
19
+ __commit_id__: str | None
30
20
 
31
- __version__ = version = '0.0.7.dev332'
32
- __version_tuple__ = version_tuple = (0, 0, 7, 'dev332')
21
+ __version__ = version = '0.0.8'
22
+ __version_tuple__ = version_tuple = (0, 0, 8)
33
23
 
34
- __commit_id__ = commit_id = None
24
+ __commit_id__ = commit_id = 'g2b4aae01d'
junifer/api/__init__.pyi CHANGED
@@ -1,4 +1,19 @@
1
- __all__ = ["decorators", "collect", "queue", "run", "reset", "list_elements"]
1
+ __all__ = [
2
+ "decorators",
3
+ "collect",
4
+ "queue",
5
+ "run",
6
+ "reset",
7
+ "list_elements",
8
+ "parse_yaml",
9
+ ]
2
10
 
3
11
  from . import decorators
4
- from .functions import collect, list_elements, reset, run, queue
12
+ from .functions import (
13
+ collect,
14
+ list_elements,
15
+ parse_yaml,
16
+ reset,
17
+ run,
18
+ queue,
19
+ )
junifer/api/functions.py CHANGED
@@ -5,10 +5,15 @@
5
5
  # Synchon Mandal <s.mandal@fz-juelich.de>
6
6
  # License: AGPL
7
7
 
8
+ import atexit
9
+ import importlib
10
+ import importlib.util
8
11
  import os
9
12
  import shutil
13
+ import sys
10
14
  from pathlib import Path
11
- from typing import Optional, Union
15
+
16
+ import structlog
12
17
 
13
18
  from ..api.queue_context import GnuParallelLocalAdapter, HTCondorAdapter
14
19
  from ..datagrabber import BaseDataGrabber
@@ -27,10 +32,20 @@ from ..typing import (
27
32
  PreprocessorLike,
28
33
  StorageLike,
29
34
  )
30
- from ..utils import logger, raise_error, warn_with_log, yaml
35
+ from ..utils import raise_error, warn_with_log, yaml
36
+
31
37
 
38
+ __all__ = [
39
+ "collect",
40
+ "list_elements",
41
+ "parse_yaml",
42
+ "queue",
43
+ "reset",
44
+ "run",
45
+ ]
32
46
 
33
- __all__ = ["collect", "list_elements", "queue", "reset", "run"]
47
+ _log = structlog.get_logger("junifer")
48
+ logger = _log.bind(pkg="api")
34
49
 
35
50
 
36
51
  def _get_datagrabber(datagrabber_config: dict) -> DataGrabberLike:
@@ -121,13 +136,52 @@ def _get_storage(storage_config: dict) -> StorageLike:
121
136
  )
122
137
 
123
138
 
139
+ def _get_workdir_params(workdir: str | Path | dict | None) -> dict:
140
+ """Get the parameters of the working directory manager.
141
+
142
+ Parameters
143
+ ----------
144
+ workdir : str or pathlib.Path or dict or None
145
+ The working directory as a path, or as a dictionary with the keys
146
+ ``path`` and ``cleanup`` (default True). If None, the default of
147
+ :class:`.WorkDirManager` is used.
148
+
149
+ Returns
150
+ -------
151
+ dict
152
+ The parameters for :class:`.WorkDirManager`.
153
+
154
+ """
155
+ if isinstance(workdir, dict):
156
+ return {
157
+ "workdir": Path(workdir["path"]),
158
+ "cleanup": workdir.get("cleanup", True),
159
+ }
160
+ if workdir is None:
161
+ return {"workdir": None, "cleanup": True}
162
+ return {"workdir": Path(workdir), "cleanup": True}
163
+
164
+
165
+ def _setup_workdir(workdir: str | Path | dict | None) -> None:
166
+ """Set up the working directory manager.
167
+
168
+ Parameters
169
+ ----------
170
+ workdir : str or pathlib.Path or dict or None
171
+ The working directory (see :func:`_get_workdir_params`).
172
+
173
+ """
174
+ WorkDirManager(**_get_workdir_params(workdir))
175
+ atexit.register(WorkDirManager()._cleanup)
176
+
177
+
124
178
  def run(
125
- workdir: Union[str, Path, dict],
179
+ workdir: str | Path | dict,
126
180
  datagrabber: dict,
127
181
  markers: list[dict],
128
182
  storage: dict,
129
- preprocessors: Optional[list[dict]] = None,
130
- elements: Optional[Elements] = None,
183
+ preprocessors: list[dict] | None = None,
184
+ elements: Elements | None = None,
131
185
  ) -> None:
132
186
  """Run the pipeline on the selected element.
133
187
 
@@ -165,24 +219,15 @@ def run(
165
219
  If invalid element selectors are found.
166
220
 
167
221
  """
168
- # Conditional to handle workdir config
169
- if isinstance(workdir, (str, Path)):
170
- if isinstance(workdir, str):
171
- workdir = {"workdir": Path(workdir), "cleanup": True}
172
- else:
173
- workdir = {"workdir": workdir, "cleanup": True}
174
- elif isinstance(workdir, dict):
175
- workdir["workdir"] = workdir.pop("path")
176
-
177
222
  # Initiate working directory manager with correct variation
178
- if not workdir["cleanup"]:
223
+ if not _get_workdir_params(workdir)["cleanup"]:
179
224
  if elements is None or len(elements) > 1:
180
225
  raise_error(
181
226
  "Cannot disable `workdir.cleanup` as "
182
227
  f"{len(elements) if elements is not None else 'all'} "
183
228
  "elements will be processed"
184
229
  )
185
- WorkDirManager(**workdir)
230
+ _setup_workdir(workdir)
186
231
 
187
232
  # Get datagrabber to use
188
233
  datagrabber_object = _get_datagrabber(datagrabber.copy())
@@ -216,28 +261,15 @@ def run(
216
261
  # Fit elements
217
262
  with datagrabber_object:
218
263
  if elements is not None:
219
- # Keep track of valid selectors
220
- valid_elements = []
221
- for t_element in datagrabber_object.filter(elements):
222
- valid_elements.append(t_element)
223
- mc.fit(datagrabber_object[t_element])
224
- # Compute invalid selectors
225
- invalid_elements = set(elements) - set(valid_elements)
226
- # Report if invalid selectors are found
227
- if invalid_elements:
228
- raise_error(
229
- msg=(
230
- "The following element selectors are invalid:\n"
231
- f"{invalid_elements}"
232
- ),
233
- klass=RuntimeError,
234
- )
264
+ # Only get the elements of the dataset for partial selectors
265
+ to_fit = datagrabber_object.select_elements(elements)
235
266
  else:
236
- for t_element in datagrabber_object:
237
- mc.fit(datagrabber_object[t_element])
267
+ to_fit = datagrabber_object.get_elements()
268
+ for t_element in to_fit:
269
+ mc.fit(datagrabber_object[t_element])
238
270
 
239
271
 
240
- def collect(storage: dict) -> None:
272
+ def collect(storage: dict, workdir: str | Path | dict | None = None) -> None:
241
273
  """Collect and store data.
242
274
 
243
275
  Parameters
@@ -246,8 +278,12 @@ def collect(storage: dict) -> None:
246
278
  Storage to use. Must have a key ``kind`` with the kind of
247
279
  storage to use. All other keys are passed to the storage
248
280
  constructor.
281
+ workdir : str or pathlib.Path or dict or None, optional
282
+ The working directory, as in :func:`.run`. If None, the default of
283
+ :class:`.WorkDirManager` is used (default None).
249
284
 
250
285
  """
286
+ _setup_workdir(workdir)
251
287
  logger.info(f"Collecting data using {storage['kind']}")
252
288
  logger.debug(f"\tStorage params: {storage}")
253
289
  if "single_output" not in storage:
@@ -263,8 +299,8 @@ def queue(
263
299
  kind: str,
264
300
  jobname: str = "junifer_job",
265
301
  overwrite: bool = False,
266
- elements: Optional[Elements] = None,
267
- **kwargs: Union[str, int, bool, dict, tuple, list],
302
+ elements: Elements | None = None,
303
+ **kwargs: str | int | bool | dict | tuple | list,
268
304
  ) -> None:
269
305
  """Queue a job to be executed later.
270
306
 
@@ -291,6 +327,7 @@ def queue(
291
327
  if the ``jobdir`` exists and ``overwrite = False``.
292
328
 
293
329
  """
330
+ _setup_workdir(config.get("workdir"))
294
331
  valid_kind = ["HTCondor", "GNUParallelLocal"]
295
332
  if kind not in valid_kind:
296
333
  raise_error(
@@ -394,6 +431,7 @@ def reset(config: dict) -> None:
394
431
  The configuration to be used for resetting.
395
432
 
396
433
  """
434
+ _setup_workdir(config.get("workdir"))
397
435
  # Fetch storage
398
436
  storage = config["storage"]
399
437
  storage_uri = Path(storage["uri"])
@@ -425,7 +463,8 @@ def reset(config: dict) -> None:
425
463
 
426
464
  def list_elements(
427
465
  datagrabber: dict,
428
- elements: Optional[Elements] = None,
466
+ elements: Elements | None = None,
467
+ workdir: str | Path | dict | None = None,
429
468
  ) -> str:
430
469
  """List elements of the datagrabber filtered using `elements`.
431
470
 
@@ -438,8 +477,13 @@ def list_elements(
438
477
  elements : list or None, optional
439
478
  Element(s) to filter using. Will be used to index the DataGrabber
440
479
  (default None).
480
+ workdir : str or pathlib.Path or dict or None, optional
481
+ Directory where the DataGrabber will be used, as in :func:`.run`.
482
+ If None, the default of :class:`.WorkDirManager` is used
483
+ (default None).
441
484
 
442
485
  """
486
+ _setup_workdir(workdir)
443
487
  # Get datagrabber to use
444
488
  datagrabber_object = _get_datagrabber(datagrabber)
445
489
 
@@ -462,3 +506,142 @@ def list_elements(
462
506
  elements_to_list.append(str_element)
463
507
 
464
508
  return "\n".join(elements_to_list)
509
+
510
+
511
+ def parse_yaml(filepath: str | Path) -> dict: # noqa: C901
512
+ """Parse YAML.
513
+
514
+ Parameters
515
+ ----------
516
+ filepath : str or pathlib.Path
517
+ The filepath to read from.
518
+
519
+ Returns
520
+ -------
521
+ dict
522
+ The contents represented as dictionary.
523
+
524
+ """
525
+ # Convert str to Path
526
+ if not isinstance(filepath, Path):
527
+ filepath = Path(filepath)
528
+
529
+ logger.info(f"Parsing yaml file: {filepath.absolute()!s}")
530
+ # Filepath existence check
531
+ if not filepath.exists():
532
+ raise_error(f"File does not exist: {filepath.absolute()!s}")
533
+ # Filepath reading
534
+ contents = yaml.load(filepath)
535
+ if "elements" in contents:
536
+ if contents["elements"] is None:
537
+ raise_error(
538
+ "The elements key was defined but its content is empty. "
539
+ "Please define the elements to operate on or remove the key."
540
+ )
541
+ # load modules
542
+ if "with" in contents:
543
+ to_load = contents["with"]
544
+ # Convert load modules to list
545
+ if not isinstance(to_load, list):
546
+ to_load = [to_load]
547
+ # Initialize list to have absolute paths for custom modules
548
+ final_to_load = []
549
+ for t_module in to_load:
550
+ if t_module.endswith(".py"):
551
+ logger.debug(f"Importing file: {t_module}")
552
+ # This resolves both absolute and relative paths
553
+ file_path = filepath.parent / t_module
554
+ if not file_path.exists():
555
+ raise_error(
556
+ f"File in 'with' section does not exist: {file_path}"
557
+ )
558
+ # Add the parent directory to the sys.path so that the
559
+ # any imports from this module work correctly
560
+ t_path = str(file_path.parent)
561
+ if t_path not in sys.path:
562
+ sys.path.append(str(file_path.parent))
563
+
564
+ spec = importlib.util.spec_from_file_location(
565
+ t_module, file_path
566
+ )
567
+ module = importlib.util.module_from_spec(spec) # type: ignore
568
+ sys.modules[t_module] = module
569
+ spec.loader.exec_module(module) # type: ignore
570
+
571
+ # Add absolute path to final list
572
+ final_to_load.append(str(file_path.resolve()))
573
+
574
+ # Check if the module has junifer_module_deps function
575
+ if hasattr(module, "junifer_module_deps"):
576
+ logger.debug(
577
+ f"Module {t_module} has junifer_module_deps function"
578
+ )
579
+ # Get the dependencies
580
+ deps = module.junifer_module_deps()
581
+ # Add the dependencies to the final list
582
+ for dep in deps:
583
+ if dep not in final_to_load:
584
+ final_to_load.append(
585
+ str((file_path.parent / dep).resolve())
586
+ )
587
+ else:
588
+ logger.info(f"Importing module: {t_module}")
589
+ importlib.import_module(t_module)
590
+ # Add module to final list
591
+ final_to_load.append(t_module)
592
+
593
+ # Replace modules to be loaded so that custom modules will take the
594
+ # absolute path. This was not the case as found in #224. Similar thing
595
+ # is done with the storage URI below.
596
+ contents["with"] = final_to_load
597
+
598
+ # Compute path for the URI parameter in storage files that are relative
599
+ # This is a tricky thing that appeared in #127. The problem is that
600
+ # the path in the URI parameter is relative to YAML file, not to the
601
+ # current working directory. If we leave it as is in the contents
602
+ # dict, then it will be used later in the ``build`` function as is,
603
+ # which will be computed relative to the current working directory.
604
+ # The solution is to compute the absolute path and replace the
605
+ # relative path in the contents dict with the absolute path.
606
+
607
+ # Check if the storage file is defined
608
+ if "storage" in contents:
609
+ if "uri" in contents["storage"]:
610
+ # Check if the storage file is relative
611
+ uri_path = Path(contents["storage"]["uri"])
612
+ if not uri_path.is_absolute():
613
+ # Compute the absolute path
614
+ contents["storage"]["uri"] = str(
615
+ (filepath.parent / uri_path).resolve()
616
+ )
617
+
618
+ # Compute the absolute path of the data directory of the datagrabber (and
619
+ # of the datagrabbers of a MultipleDataGrabber) if it is relative; same
620
+ # motivation as above. Otherwise, it would be relative to the current
621
+ # working directory, which is the job directory when queueing.
622
+ if "datagrabber" in contents:
623
+ datagrabbers = [
624
+ contents["datagrabber"],
625
+ *contents["datagrabber"].get("datagrabbers", []),
626
+ ]
627
+ for datagrabber in datagrabbers:
628
+ if "datadir" in datagrabber:
629
+ datadir = Path(datagrabber["datadir"])
630
+ if not datadir.is_absolute():
631
+ datagrabber["datadir"] = str(
632
+ (filepath.parent / datadir).resolve()
633
+ )
634
+
635
+ # Allow relative path if queue env kind is venv; same motivation as above
636
+ if "queue" in contents:
637
+ if "env" in contents["queue"]:
638
+ if "venv" == contents["queue"]["env"]["kind"]:
639
+ # Check if the env name is relative
640
+ venv_path = Path(contents["queue"]["env"]["name"])
641
+ if not venv_path.is_absolute():
642
+ # Compute the absolute path
643
+ contents["queue"]["env"]["name"] = str(
644
+ (filepath.parent / venv_path).resolve()
645
+ )
646
+
647
+ return contents
@@ -1,5 +1,13 @@
1
- __all__ = ["QueueContextAdapter", "HTCondorAdapter", "GnuParallelLocalAdapter"]
1
+ __all__ = [
2
+ "QueueContextAdapter",
3
+ "EnvKind",
4
+ "EnvShell",
5
+ "QueueContextEnv",
6
+ "HTCondorAdapter",
7
+ "HTCondorCollect",
8
+ "GnuParallelLocalAdapter",
9
+ ]
2
10
 
3
- from .queue_context_adapter import QueueContextAdapter
4
- from .htcondor_adapter import HTCondorAdapter
11
+ from .queue_context_adapter import QueueContextAdapter, EnvKind, EnvShell, QueueContextEnv
12
+ from .htcondor_adapter import HTCondorAdapter, HTCondorCollect
5
13
  from .gnu_parallel_local_adapter import GnuParallelLocalAdapter