junifer 0.0.4.dev829__py3-none-any.whl → 0.0.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- junifer/__init__.py +17 -0
- junifer/_version.py +2 -2
- junifer/api/__init__.py +4 -1
- junifer/api/cli.py +91 -1
- junifer/api/decorators.py +9 -0
- junifer/api/functions.py +56 -10
- junifer/api/parser.py +3 -0
- junifer/api/queue_context/__init__.py +4 -1
- junifer/api/queue_context/gnu_parallel_local_adapter.py +16 -6
- junifer/api/queue_context/htcondor_adapter.py +16 -5
- junifer/api/queue_context/tests/test_gnu_parallel_local_adapter.py +41 -12
- junifer/api/queue_context/tests/test_htcondor_adapter.py +48 -15
- junifer/api/res/afni/run_afni_docker.sh +1 -1
- junifer/api/res/ants/run_ants_docker.sh +1 -1
- junifer/api/res/freesurfer/mri_binarize +3 -0
- junifer/api/res/freesurfer/mri_mc +3 -0
- junifer/api/res/freesurfer/mri_pretess +3 -0
- junifer/api/res/freesurfer/mris_convert +3 -0
- junifer/api/res/freesurfer/run_freesurfer_docker.sh +61 -0
- junifer/api/res/fsl/run_fsl_docker.sh +1 -1
- junifer/api/res/{run_conda.sh → run_conda.bash} +1 -1
- junifer/api/res/run_conda.zsh +23 -0
- junifer/api/res/run_venv.bash +22 -0
- junifer/api/res/{run_venv.sh → run_venv.zsh} +1 -1
- junifer/api/tests/test_api_utils.py +4 -2
- junifer/api/tests/test_cli.py +83 -0
- junifer/api/tests/test_functions.py +27 -2
- junifer/configs/__init__.py +1 -1
- junifer/configs/juseless/__init__.py +4 -1
- junifer/configs/juseless/datagrabbers/__init__.py +10 -1
- junifer/configs/juseless/datagrabbers/aomic_id1000_vbm.py +4 -3
- junifer/configs/juseless/datagrabbers/camcan_vbm.py +3 -0
- junifer/configs/juseless/datagrabbers/ixi_vbm.py +4 -3
- junifer/configs/juseless/datagrabbers/tests/test_ucla.py +1 -3
- junifer/configs/juseless/datagrabbers/ucla.py +12 -9
- junifer/configs/juseless/datagrabbers/ukb_vbm.py +3 -0
- junifer/data/__init__.py +21 -1
- junifer/data/coordinates.py +10 -19
- junifer/data/masks/ukb/UKB_15K_GM_template.nii.gz +0 -0
- junifer/data/masks.py +58 -87
- junifer/data/parcellations.py +14 -3
- junifer/data/template_spaces.py +4 -1
- junifer/data/tests/test_masks.py +26 -37
- junifer/data/utils.py +3 -0
- junifer/datagrabber/__init__.py +18 -1
- junifer/datagrabber/aomic/__init__.py +3 -0
- junifer/datagrabber/aomic/id1000.py +70 -37
- junifer/datagrabber/aomic/piop1.py +69 -36
- junifer/datagrabber/aomic/piop2.py +71 -38
- junifer/datagrabber/aomic/tests/test_id1000.py +44 -100
- junifer/datagrabber/aomic/tests/test_piop1.py +65 -108
- junifer/datagrabber/aomic/tests/test_piop2.py +45 -102
- junifer/datagrabber/base.py +13 -6
- junifer/datagrabber/datalad_base.py +13 -1
- junifer/datagrabber/dmcc13_benchmark.py +36 -53
- junifer/datagrabber/hcp1200/__init__.py +3 -0
- junifer/datagrabber/hcp1200/datalad_hcp1200.py +3 -0
- junifer/datagrabber/hcp1200/hcp1200.py +4 -1
- junifer/datagrabber/multiple.py +45 -6
- junifer/datagrabber/pattern.py +170 -62
- junifer/datagrabber/pattern_datalad.py +25 -12
- junifer/datagrabber/pattern_validation_mixin.py +388 -0
- junifer/datagrabber/tests/test_datalad_base.py +4 -4
- junifer/datagrabber/tests/test_dmcc13_benchmark.py +46 -19
- junifer/datagrabber/tests/test_multiple.py +161 -84
- junifer/datagrabber/tests/test_pattern.py +45 -0
- junifer/datagrabber/tests/test_pattern_datalad.py +4 -4
- junifer/datagrabber/tests/test_pattern_validation_mixin.py +249 -0
- junifer/datareader/__init__.py +4 -1
- junifer/datareader/default.py +95 -43
- junifer/external/BrainPrint/brainprint/__init__.py +4 -0
- junifer/external/BrainPrint/brainprint/_version.py +3 -0
- junifer/external/BrainPrint/brainprint/asymmetry.py +91 -0
- junifer/external/BrainPrint/brainprint/brainprint.py +441 -0
- junifer/external/BrainPrint/brainprint/surfaces.py +258 -0
- junifer/external/BrainPrint/brainprint/utils/__init__.py +1 -0
- junifer/external/BrainPrint/brainprint/utils/_config.py +112 -0
- junifer/external/BrainPrint/brainprint/utils/utils.py +188 -0
- junifer/external/__init__.py +1 -1
- junifer/external/nilearn/__init__.py +5 -1
- junifer/external/nilearn/junifer_connectivity_measure.py +483 -0
- junifer/external/nilearn/junifer_nifti_spheres_masker.py +23 -9
- junifer/external/nilearn/tests/test_junifer_connectivity_measure.py +1089 -0
- junifer/external/nilearn/tests/test_junifer_nifti_spheres_masker.py +76 -1
- junifer/markers/__init__.py +23 -1
- junifer/markers/base.py +68 -28
- junifer/markers/brainprint.py +459 -0
- junifer/markers/collection.py +10 -2
- junifer/markers/complexity/__init__.py +10 -0
- junifer/markers/complexity/complexity_base.py +26 -43
- junifer/markers/complexity/hurst_exponent.py +3 -0
- junifer/markers/complexity/multiscale_entropy_auc.py +3 -0
- junifer/markers/complexity/perm_entropy.py +3 -0
- junifer/markers/complexity/range_entropy.py +3 -0
- junifer/markers/complexity/range_entropy_auc.py +3 -0
- junifer/markers/complexity/sample_entropy.py +3 -0
- junifer/markers/complexity/tests/test_hurst_exponent.py +11 -3
- junifer/markers/complexity/tests/test_multiscale_entropy_auc.py +11 -3
- junifer/markers/complexity/tests/test_perm_entropy.py +11 -3
- junifer/markers/complexity/tests/test_range_entropy.py +11 -3
- junifer/markers/complexity/tests/test_range_entropy_auc.py +11 -3
- junifer/markers/complexity/tests/test_sample_entropy.py +11 -3
- junifer/markers/complexity/tests/test_weighted_perm_entropy.py +11 -3
- junifer/markers/complexity/weighted_perm_entropy.py +3 -0
- junifer/markers/ets_rss.py +27 -42
- junifer/markers/falff/__init__.py +3 -0
- junifer/markers/falff/_afni_falff.py +5 -2
- junifer/markers/falff/_junifer_falff.py +3 -0
- junifer/markers/falff/falff_base.py +20 -46
- junifer/markers/falff/falff_parcels.py +56 -27
- junifer/markers/falff/falff_spheres.py +60 -29
- junifer/markers/falff/tests/test_falff_parcels.py +39 -23
- junifer/markers/falff/tests/test_falff_spheres.py +39 -23
- junifer/markers/functional_connectivity/__init__.py +9 -0
- junifer/markers/functional_connectivity/crossparcellation_functional_connectivity.py +63 -60
- junifer/markers/functional_connectivity/edge_functional_connectivity_parcels.py +45 -32
- junifer/markers/functional_connectivity/edge_functional_connectivity_spheres.py +49 -36
- junifer/markers/functional_connectivity/functional_connectivity_base.py +71 -70
- junifer/markers/functional_connectivity/functional_connectivity_parcels.py +34 -25
- junifer/markers/functional_connectivity/functional_connectivity_spheres.py +40 -30
- junifer/markers/functional_connectivity/tests/test_crossparcellation_functional_connectivity.py +11 -7
- junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_parcels.py +27 -7
- junifer/markers/functional_connectivity/tests/test_edge_functional_connectivity_spheres.py +28 -12
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_parcels.py +35 -11
- junifer/markers/functional_connectivity/tests/test_functional_connectivity_spheres.py +36 -62
- junifer/markers/parcel_aggregation.py +47 -61
- junifer/markers/reho/__init__.py +3 -0
- junifer/markers/reho/_afni_reho.py +5 -2
- junifer/markers/reho/_junifer_reho.py +4 -1
- junifer/markers/reho/reho_base.py +8 -27
- junifer/markers/reho/reho_parcels.py +28 -17
- junifer/markers/reho/reho_spheres.py +27 -18
- junifer/markers/reho/tests/test_reho_parcels.py +8 -3
- junifer/markers/reho/tests/test_reho_spheres.py +8 -3
- junifer/markers/sphere_aggregation.py +43 -59
- junifer/markers/temporal_snr/__init__.py +3 -0
- junifer/markers/temporal_snr/temporal_snr_base.py +23 -32
- junifer/markers/temporal_snr/temporal_snr_parcels.py +9 -6
- junifer/markers/temporal_snr/temporal_snr_spheres.py +9 -6
- junifer/markers/temporal_snr/tests/test_temporal_snr_parcels.py +6 -3
- junifer/markers/temporal_snr/tests/test_temporal_snr_spheres.py +6 -3
- junifer/markers/tests/test_brainprint.py +58 -0
- junifer/markers/tests/test_collection.py +9 -8
- junifer/markers/tests/test_ets_rss.py +15 -9
- junifer/markers/tests/test_markers_base.py +17 -18
- junifer/markers/tests/test_parcel_aggregation.py +93 -32
- junifer/markers/tests/test_sphere_aggregation.py +72 -19
- junifer/onthefly/__init__.py +4 -1
- junifer/onthefly/read_transform.py +3 -0
- junifer/pipeline/__init__.py +9 -1
- junifer/pipeline/pipeline_step_mixin.py +21 -4
- junifer/pipeline/registry.py +3 -0
- junifer/pipeline/singleton.py +3 -0
- junifer/pipeline/tests/test_registry.py +1 -1
- junifer/pipeline/update_meta_mixin.py +3 -0
- junifer/pipeline/utils.py +67 -1
- junifer/pipeline/workdir_manager.py +3 -0
- junifer/preprocess/__init__.py +10 -2
- junifer/preprocess/base.py +6 -3
- junifer/preprocess/confounds/__init__.py +3 -0
- junifer/preprocess/confounds/fmriprep_confound_remover.py +47 -60
- junifer/preprocess/confounds/tests/test_fmriprep_confound_remover.py +72 -113
- junifer/preprocess/smoothing/__init__.py +9 -0
- junifer/preprocess/smoothing/_afni_smoothing.py +119 -0
- junifer/preprocess/smoothing/_fsl_smoothing.py +116 -0
- junifer/preprocess/smoothing/_nilearn_smoothing.py +69 -0
- junifer/preprocess/smoothing/smoothing.py +174 -0
- junifer/preprocess/smoothing/tests/test_smoothing.py +94 -0
- junifer/preprocess/warping/__init__.py +3 -0
- junifer/preprocess/warping/_ants_warper.py +3 -0
- junifer/preprocess/warping/_fsl_warper.py +3 -0
- junifer/stats.py +4 -1
- junifer/storage/__init__.py +9 -1
- junifer/storage/base.py +40 -1
- junifer/storage/hdf5.py +71 -9
- junifer/storage/pandas_base.py +3 -0
- junifer/storage/sqlite.py +3 -0
- junifer/storage/tests/test_hdf5.py +82 -10
- junifer/storage/utils.py +9 -0
- junifer/testing/__init__.py +4 -1
- junifer/testing/datagrabbers.py +13 -6
- junifer/testing/tests/test_partlycloudytesting_datagrabber.py +7 -7
- junifer/testing/utils.py +3 -0
- junifer/utils/__init__.py +13 -2
- junifer/utils/fs.py +3 -0
- junifer/utils/helpers.py +32 -1
- junifer/utils/logging.py +33 -4
- junifer/utils/tests/test_logging.py +8 -0
- {junifer-0.0.4.dev829.dist-info → junifer-0.0.5.dist-info}/METADATA +17 -16
- junifer-0.0.5.dist-info/RECORD +275 -0
- {junifer-0.0.4.dev829.dist-info → junifer-0.0.5.dist-info}/WHEEL +1 -1
- junifer/datagrabber/tests/test_datagrabber_utils.py +0 -218
- junifer/datagrabber/utils.py +0 -230
- junifer/preprocess/ants/__init__.py +0 -4
- junifer/preprocess/ants/ants_apply_transforms_warper.py +0 -185
- junifer/preprocess/ants/tests/test_ants_apply_transforms_warper.py +0 -56
- junifer/preprocess/bold_warper.py +0 -265
- junifer/preprocess/fsl/__init__.py +0 -4
- junifer/preprocess/fsl/apply_warper.py +0 -179
- junifer/preprocess/fsl/tests/test_apply_warper.py +0 -45
- junifer/preprocess/tests/test_bold_warper.py +0 -159
- junifer-0.0.4.dev829.dist-info/RECORD +0 -257
- {junifer-0.0.4.dev829.dist-info → junifer-0.0.5.dist-info}/AUTHORS.rst +0 -0
- {junifer-0.0.4.dev829.dist-info → junifer-0.0.5.dist-info}/LICENSE.md +0 -0
- {junifer-0.0.4.dev829.dist-info → junifer-0.0.5.dist-info}/entry_points.txt +0 -0
- {junifer-0.0.4.dev829.dist-info → junifer-0.0.5.dist-info}/top_level.txt +0 -0
junifer/__init__.py
CHANGED
@@ -20,3 +20,20 @@ from . import (
|
|
20
20
|
onthefly,
|
21
21
|
)
|
22
22
|
from ._version import __version__
|
23
|
+
|
24
|
+
|
25
|
+
__all__ = [
|
26
|
+
"api",
|
27
|
+
"configs",
|
28
|
+
"data",
|
29
|
+
"datagrabber",
|
30
|
+
"datareader",
|
31
|
+
"markers",
|
32
|
+
"pipeline",
|
33
|
+
"preprocess",
|
34
|
+
"stats",
|
35
|
+
"storage",
|
36
|
+
"utils",
|
37
|
+
"external",
|
38
|
+
"onthefly",
|
39
|
+
]
|
junifer/_version.py
CHANGED
@@ -12,5 +12,5 @@ __version__: str
|
|
12
12
|
__version_tuple__: VERSION_TUPLE
|
13
13
|
version_tuple: VERSION_TUPLE
|
14
14
|
|
15
|
-
__version__ = version = '0.0.
|
16
|
-
__version_tuple__ = version_tuple = (0, 0,
|
15
|
+
__version__ = version = '0.0.5'
|
16
|
+
__version_tuple__ = version_tuple = (0, 0, 5)
|
junifer/api/__init__.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
"""
|
1
|
+
"""Public API and CLI components."""
|
2
2
|
|
3
3
|
# Authors: Federico Raimondo <f.raimondo@fz-juelich.de>
|
4
4
|
# Synchon Mandal <s.mandal@fz-juelich.de>
|
@@ -7,3 +7,6 @@
|
|
7
7
|
from . import decorators
|
8
8
|
from .cli import cli
|
9
9
|
from .functions import collect, queue, run
|
10
|
+
|
11
|
+
|
12
|
+
__all__ = ["decorators", "cli", "collect", "queue", "run"]
|
junifer/api/cli.py
CHANGED
@@ -8,7 +8,7 @@ import pathlib
|
|
8
8
|
import subprocess
|
9
9
|
import sys
|
10
10
|
from pathlib import Path
|
11
|
-
from typing import Dict, List, Tuple, Union
|
11
|
+
from typing import Dict, List, Optional, Tuple, Union
|
12
12
|
|
13
13
|
import click
|
14
14
|
import pandas as pd
|
@@ -20,6 +20,7 @@ from ..utils.logging import (
|
|
20
20
|
warn_with_log,
|
21
21
|
)
|
22
22
|
from .functions import collect as api_collect
|
23
|
+
from .functions import list_elements as api_list_elements
|
23
24
|
from .functions import queue as api_queue
|
24
25
|
from .functions import reset as api_reset
|
25
26
|
from .functions import run as api_run
|
@@ -451,6 +452,69 @@ def reset(
|
|
451
452
|
api_reset(config)
|
452
453
|
|
453
454
|
|
455
|
+
@cli.command()
|
456
|
+
@click.argument(
|
457
|
+
"filepath",
|
458
|
+
type=click.Path(
|
459
|
+
exists=True, readable=True, dir_okay=False, path_type=pathlib.Path
|
460
|
+
),
|
461
|
+
)
|
462
|
+
@click.option("--element", type=str, multiple=True)
|
463
|
+
@click.option(
|
464
|
+
"-o",
|
465
|
+
"--output-file",
|
466
|
+
type=click.Path(dir_okay=False, writable=True, path_type=pathlib.Path),
|
467
|
+
)
|
468
|
+
@click.option(
|
469
|
+
"-v",
|
470
|
+
"--verbose",
|
471
|
+
type=click.UNPROCESSED,
|
472
|
+
callback=_validate_verbose,
|
473
|
+
default="info",
|
474
|
+
)
|
475
|
+
def list_elements(
|
476
|
+
filepath: click.Path,
|
477
|
+
element: Tuple[str],
|
478
|
+
output_file: Optional[click.Path],
|
479
|
+
verbose: Union[str, int],
|
480
|
+
) -> None:
|
481
|
+
"""Element listing command for CLI.
|
482
|
+
|
483
|
+
\f
|
484
|
+
|
485
|
+
Parameters
|
486
|
+
----------
|
487
|
+
filepath : click.Path
|
488
|
+
The filepath to the configuration file.
|
489
|
+
element : tuple of str
|
490
|
+
The element to operate on.
|
491
|
+
output_file : click.Path or None
|
492
|
+
The path to write the output to. If not None, writing to
|
493
|
+
stdout is not performed.
|
494
|
+
verbose : click.Choice
|
495
|
+
The verbosity level: warning, info or debug (default "info").
|
496
|
+
|
497
|
+
"""
|
498
|
+
configure_logging(level=verbose)
|
499
|
+
# Parse YAML
|
500
|
+
config = parse_yaml(filepath) # type: ignore
|
501
|
+
# Fetch datagrabber
|
502
|
+
datagrabber = config["datagrabber"]
|
503
|
+
# Parse elements
|
504
|
+
elements = _parse_elements(element, config)
|
505
|
+
# Perform operation
|
506
|
+
listed_elements = api_list_elements(
|
507
|
+
datagrabber=datagrabber,
|
508
|
+
elements=elements,
|
509
|
+
)
|
510
|
+
# Check if output file is provided
|
511
|
+
if output_file is not None:
|
512
|
+
output_file.touch()
|
513
|
+
output_file.write_text(listed_elements)
|
514
|
+
else:
|
515
|
+
click.secho(listed_elements, fg="blue")
|
516
|
+
|
517
|
+
|
454
518
|
@cli.group()
|
455
519
|
def setup() -> None: # pragma: no cover
|
456
520
|
"""Configure commands for Junifer."""
|
@@ -524,3 +588,29 @@ def ants_docker() -> None: # pragma: no cover
|
|
524
588
|
export PATH="$PATH:{ants_wrappers_path}"
|
525
589
|
"""
|
526
590
|
click.secho(msg, fg="blue")
|
591
|
+
|
592
|
+
|
593
|
+
@setup.command("freesurfer-docker")
|
594
|
+
def freesurfer_docker() -> None: # pragma: no cover
|
595
|
+
"""Configure FreeSurfer-Docker wrappers."""
|
596
|
+
import junifer
|
597
|
+
|
598
|
+
pkg_path = Path(junifer.__path__[0]) # type: ignore
|
599
|
+
fs_wrappers_path = pkg_path / "api" / "res" / "freesurfer"
|
600
|
+
msg = f"""
|
601
|
+
Installation instructions for FreeSurfer-Docker wrappers:
|
602
|
+
|
603
|
+
1. Install Docker: https://docs.docker.com/get-docker/
|
604
|
+
|
605
|
+
2. Get the FreeSurfer-Docker image by running this on the command line:
|
606
|
+
|
607
|
+
docker pull freesurfer/freesurfer
|
608
|
+
|
609
|
+
3. Get license from: https://surfer.nmr.mgh.harvard.edu/registration.html .
|
610
|
+
You can skip this step if you already have one.
|
611
|
+
|
612
|
+
4. Add this line to the ~/.bashrc or ~/.zshrc file:
|
613
|
+
|
614
|
+
export PATH="$PATH:{fs_wrappers_path}"
|
615
|
+
"""
|
616
|
+
click.secho(msg, fg="blue")
|
junifer/api/decorators.py
CHANGED
@@ -10,6 +10,15 @@ from typing import Type
|
|
10
10
|
from ..pipeline.registry import register
|
11
11
|
|
12
12
|
|
13
|
+
__all__ = [
|
14
|
+
"register_datagrabber",
|
15
|
+
"register_datareader",
|
16
|
+
"register_preprocessor",
|
17
|
+
"register_marker",
|
18
|
+
"register_storage",
|
19
|
+
]
|
20
|
+
|
21
|
+
|
13
22
|
def register_datagrabber(klass: Type) -> Type:
|
14
23
|
"""Register DataGrabber.
|
15
24
|
|
junifer/api/functions.py
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
# Synchon Mandal <s.mandal@fz-juelich.de>
|
6
6
|
# License: AGPL
|
7
7
|
|
8
|
+
import os
|
8
9
|
import shutil
|
9
10
|
import typing
|
10
11
|
from pathlib import Path
|
@@ -22,6 +23,9 @@ from .queue_context import GnuParallelLocalAdapter, HTCondorAdapter
|
|
22
23
|
from .utils import yaml
|
23
24
|
|
24
25
|
|
26
|
+
__all__ = ["run", "collect", "queue", "reset", "list_elements"]
|
27
|
+
|
28
|
+
|
25
29
|
def _get_datagrabber(datagrabber_config: Dict) -> BaseDataGrabber:
|
26
30
|
"""Get DataGrabber.
|
27
31
|
|
@@ -91,7 +95,7 @@ def run(
|
|
91
95
|
datagrabber : dict
|
92
96
|
DataGrabber to use. Must have a key ``kind`` with the kind of
|
93
97
|
DataGrabber to use. All other keys are passed to the DataGrabber
|
94
|
-
|
98
|
+
constructor.
|
95
99
|
markers : list of dict
|
96
100
|
List of markers to extract. Each marker is a dict with at least two
|
97
101
|
keys: ``name`` and ``kind``. The ``name`` key is used to name the
|
@@ -101,11 +105,11 @@ def run(
|
|
101
105
|
storage : dict
|
102
106
|
Storage to use. Must have a key ``kind`` with the kind of
|
103
107
|
storage to use. All other keys are passed to the storage
|
104
|
-
|
108
|
+
constructor.
|
105
109
|
preprocessors : list of dict, optional
|
106
110
|
List of preprocessors to use. Each preprocessor is a dict with at
|
107
111
|
least a key ``kind`` specifying the preprocessor to use. All other keys
|
108
|
-
are passed to the preprocessor
|
112
|
+
are passed to the preprocessor constructor (default None).
|
109
113
|
elements : str or tuple or list of str or tuple, optional
|
110
114
|
Element(s) to process. Will be used to index the DataGrabber
|
111
115
|
(default None).
|
@@ -187,7 +191,7 @@ def collect(storage: Dict) -> None:
|
|
187
191
|
storage : dict
|
188
192
|
Storage to use. Must have a key ``kind`` with the kind of
|
189
193
|
storage to use. All other keys are passed to the storage
|
190
|
-
|
194
|
+
constructor.
|
191
195
|
|
192
196
|
"""
|
193
197
|
storage_params = storage.copy()
|
@@ -339,12 +343,12 @@ def reset(config: Dict) -> None:
|
|
339
343
|
storage = config["storage"]
|
340
344
|
storage_uri = Path(storage["uri"])
|
341
345
|
logger.info(f"Deleting {storage_uri.resolve()!s}")
|
342
|
-
# Delete storage
|
346
|
+
# Delete storage
|
343
347
|
if storage_uri.exists():
|
344
|
-
# Delete files in the directory
|
345
|
-
for file in storage_uri.iterdir():
|
348
|
+
# Delete files in the job storage directory
|
349
|
+
for file in storage_uri.parent.iterdir():
|
346
350
|
file.unlink(missing_ok=True)
|
347
|
-
# Remove directory
|
351
|
+
# Remove job storage directory
|
348
352
|
storage_uri.parent.rmdir()
|
349
353
|
|
350
354
|
# Fetch job name (if present)
|
@@ -359,5 +363,47 @@ def reset(config: Dict) -> None:
|
|
359
363
|
if job_dir.exists():
|
360
364
|
# Remove files and directories
|
361
365
|
shutil.rmtree(job_dir)
|
362
|
-
# Remove directory
|
363
|
-
job_dir.parent
|
366
|
+
# Remove parent directory (if empty)
|
367
|
+
if not next(os.scandir(job_dir.parent), None):
|
368
|
+
job_dir.parent.rmdir()
|
369
|
+
|
370
|
+
|
371
|
+
def list_elements(
|
372
|
+
datagrabber: Dict,
|
373
|
+
elements: Union[str, List[Union[str, Tuple]], Tuple, None] = None,
|
374
|
+
) -> str:
|
375
|
+
"""List elements of the datagrabber filtered using `elements`.
|
376
|
+
|
377
|
+
Parameters
|
378
|
+
----------
|
379
|
+
datagrabber : dict
|
380
|
+
DataGrabber to index. Must have a key ``kind`` with the kind of
|
381
|
+
DataGrabber to use. All other keys are passed to the DataGrabber
|
382
|
+
constructor.
|
383
|
+
elements : str or tuple or list of str or tuple, optional
|
384
|
+
Element(s) to filter using. Will be used to index the DataGrabber
|
385
|
+
(default None).
|
386
|
+
|
387
|
+
"""
|
388
|
+
# Get datagrabber to use
|
389
|
+
datagrabber_object = _get_datagrabber(datagrabber)
|
390
|
+
|
391
|
+
# Fetch elements
|
392
|
+
raw_elements_to_list = []
|
393
|
+
with datagrabber_object:
|
394
|
+
if elements is not None:
|
395
|
+
for element in datagrabber_object.filter(elements):
|
396
|
+
raw_elements_to_list.append(element)
|
397
|
+
else:
|
398
|
+
for element in datagrabber_object:
|
399
|
+
raw_elements_to_list.append(element)
|
400
|
+
|
401
|
+
elements_to_list = []
|
402
|
+
for element in raw_elements_to_list:
|
403
|
+
# Stringify elements if tuple for operation
|
404
|
+
str_element = (
|
405
|
+
",".join(element) if isinstance(element, tuple) else element
|
406
|
+
)
|
407
|
+
elements_to_list.append(str_element)
|
408
|
+
|
409
|
+
return "\n".join(elements_to_list)
|
junifer/api/parser.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
"""
|
1
|
+
"""Context adapters for queueing."""
|
2
2
|
|
3
3
|
# Authors: Synchon Mandal <s.mandal@fz-juelich.de>
|
4
4
|
# License: AGPL
|
@@ -6,3 +6,6 @@
|
|
6
6
|
from .queue_context_adapter import QueueContextAdapter
|
7
7
|
from .htcondor_adapter import HTCondorAdapter
|
8
8
|
from .gnu_parallel_local_adapter import GnuParallelLocalAdapter
|
9
|
+
|
10
|
+
|
11
|
+
__all__ = ["QueueContextAdapter", "HTCondorAdapter", "GnuParallelLocalAdapter"]
|
@@ -43,7 +43,8 @@ class GnuParallelLocalAdapter(QueueContextAdapter):
|
|
43
43
|
Raises
|
44
44
|
------
|
45
45
|
ValueError
|
46
|
-
If``env`` is invalid
|
46
|
+
If ``env.kind`` is invalid or
|
47
|
+
if ``env.shell`` is invalid.
|
47
48
|
|
48
49
|
See Also
|
49
50
|
--------
|
@@ -110,13 +111,22 @@ class GnuParallelLocalAdapter(QueueContextAdapter):
|
|
110
111
|
f"must be one of {valid_env_kinds}"
|
111
112
|
)
|
112
113
|
else:
|
114
|
+
# Check shell
|
115
|
+
shell = env.get("shell", "bash")
|
116
|
+
valid_shells = ["bash", "zsh"]
|
117
|
+
if shell not in valid_shells:
|
118
|
+
raise_error(
|
119
|
+
f"Invalid value for `env.shell`: {shell}, "
|
120
|
+
f"must be one of {valid_shells}"
|
121
|
+
)
|
122
|
+
self._shell = shell
|
113
123
|
# Set variables
|
114
124
|
if env["kind"] == "local":
|
115
125
|
# No virtual environment
|
116
126
|
self._executable = "junifer"
|
117
127
|
self._arguments = ""
|
118
128
|
else:
|
119
|
-
self._executable = f"run_{env['kind']}.
|
129
|
+
self._executable = f"run_{env['kind']}.{self._shell}"
|
120
130
|
self._arguments = f"{env['name']} junifer"
|
121
131
|
self._exec_path = self._job_dir / self._executable
|
122
132
|
|
@@ -135,7 +145,7 @@ class GnuParallelLocalAdapter(QueueContextAdapter):
|
|
135
145
|
def pre_run(self) -> str:
|
136
146
|
"""Return pre-run commands."""
|
137
147
|
fixed = (
|
138
|
-
"#!/usr/bin/env
|
148
|
+
f"#!/usr/bin/env {self._shell}\n\n"
|
139
149
|
"# This script is auto-generated by junifer.\n\n"
|
140
150
|
"# Force datalad to run in non-interactive mode\n"
|
141
151
|
"DATALAD_UI_INTERACTIVE=false\n"
|
@@ -146,7 +156,7 @@ class GnuParallelLocalAdapter(QueueContextAdapter):
|
|
146
156
|
def run(self) -> str:
|
147
157
|
"""Return run commands."""
|
148
158
|
return (
|
149
|
-
"#!/usr/bin/env
|
159
|
+
f"#!/usr/bin/env {self._shell}\n\n"
|
150
160
|
"# This script is auto-generated by junifer.\n\n"
|
151
161
|
"# Run pre_run.sh\n"
|
152
162
|
f"sh {self._pre_run_path.resolve()!s}\n\n"
|
@@ -166,7 +176,7 @@ class GnuParallelLocalAdapter(QueueContextAdapter):
|
|
166
176
|
def pre_collect(self) -> str:
|
167
177
|
"""Return pre-collect commands."""
|
168
178
|
fixed = (
|
169
|
-
"#!/usr/bin/env
|
179
|
+
f"#!/usr/bin/env {self._shell}\n\n"
|
170
180
|
"# This script is auto-generated by junifer.\n"
|
171
181
|
)
|
172
182
|
var = self._pre_collect or ""
|
@@ -175,7 +185,7 @@ class GnuParallelLocalAdapter(QueueContextAdapter):
|
|
175
185
|
def collect(self) -> str:
|
176
186
|
"""Return collect commands."""
|
177
187
|
return (
|
178
|
-
"#!/usr/bin/env
|
188
|
+
f"#!/usr/bin/env {self._shell}\n\n"
|
179
189
|
"# This script is auto-generated by junifer.\n\n"
|
180
190
|
"# Run pre_collect.sh\n"
|
181
191
|
f"sh {self._pre_collect_path.resolve()!s}\n\n"
|
@@ -126,7 +126,8 @@ class HTCondorAdapter(QueueContextAdapter):
|
|
126
126
|
Raises
|
127
127
|
------
|
128
128
|
ValueError
|
129
|
-
If ``env.kind`` is invalid
|
129
|
+
If ``env.kind`` is invalid or
|
130
|
+
if ``env.shell`` is invalid.
|
130
131
|
|
131
132
|
"""
|
132
133
|
# Set env related variables
|
@@ -140,13 +141,22 @@ class HTCondorAdapter(QueueContextAdapter):
|
|
140
141
|
f"must be one of {valid_env_kinds}"
|
141
142
|
)
|
142
143
|
else:
|
144
|
+
# Check shell
|
145
|
+
shell = env.get("shell", "bash")
|
146
|
+
valid_shells = ["bash", "zsh"]
|
147
|
+
if shell not in valid_shells:
|
148
|
+
raise_error(
|
149
|
+
f"Invalid value for `env.shell`: {shell}, "
|
150
|
+
f"must be one of {valid_shells}"
|
151
|
+
)
|
152
|
+
self._shell = shell
|
143
153
|
# Set variables
|
144
154
|
if env["kind"] == "local":
|
145
155
|
# No virtual environment
|
146
156
|
self._executable = "junifer"
|
147
157
|
self._arguments = ""
|
148
158
|
else:
|
149
|
-
self._executable = f"run_{env['kind']}.
|
159
|
+
self._executable = f"run_{env['kind']}.{self._shell}"
|
150
160
|
self._arguments = f"{env['name']} junifer"
|
151
161
|
self._exec_path = self._job_dir / self._executable
|
152
162
|
|
@@ -181,7 +191,7 @@ class HTCondorAdapter(QueueContextAdapter):
|
|
181
191
|
def pre_run(self) -> str:
|
182
192
|
"""Return pre-run commands."""
|
183
193
|
fixed = (
|
184
|
-
"#!/bin/
|
194
|
+
f"#!/usr/bin/env {self._shell}\n\n"
|
185
195
|
"# This script is auto-generated by junifer.\n\n"
|
186
196
|
"# Force datalad to run in non-interactive mode\n"
|
187
197
|
"DATALAD_UI_INTERACTIVE=false\n"
|
@@ -225,12 +235,13 @@ class HTCondorAdapter(QueueContextAdapter):
|
|
225
235
|
def pre_collect(self) -> str:
|
226
236
|
"""Return pre-collect commands."""
|
227
237
|
fixed = (
|
228
|
-
"#!/bin/
|
238
|
+
f"#!/usr/bin/env {self._shell}\n\n"
|
239
|
+
"# This script is auto-generated by junifer.\n"
|
229
240
|
)
|
230
241
|
var = self._pre_collect or ""
|
231
242
|
# Add commands if collect="yes"
|
232
243
|
if self._collect == "yes":
|
233
|
-
var += 'if [ "${1}" == "4" ]; then\n
|
244
|
+
var += 'if [ "${1}" == "4" ]; then\n exit 1\nfi\n'
|
234
245
|
return fixed + "\n" + var
|
235
246
|
|
236
247
|
def collect(self) -> str:
|
@@ -12,11 +12,11 @@ import pytest
|
|
12
12
|
from junifer.api.queue_context import GnuParallelLocalAdapter
|
13
13
|
|
14
14
|
|
15
|
-
def
|
15
|
+
def test_GnuParallelLocalAdapter_env_kind_error() -> None:
|
16
16
|
"""Test error for invalid env kind."""
|
17
17
|
with pytest.raises(ValueError, match="Invalid value for `env.kind`"):
|
18
18
|
GnuParallelLocalAdapter(
|
19
|
-
job_name="
|
19
|
+
job_name="check_env_kind",
|
20
20
|
job_dir=Path("."),
|
21
21
|
yaml_config_path=Path("."),
|
22
22
|
elements=["sub01"],
|
@@ -24,6 +24,18 @@ def test_GnuParallelLocalAdapter_env_error() -> None:
|
|
24
24
|
)
|
25
25
|
|
26
26
|
|
27
|
+
def test_GnuParallelLocalAdapter_env_shell_error() -> None:
|
28
|
+
"""Test error for invalid env shell."""
|
29
|
+
with pytest.raises(ValueError, match="Invalid value for `env.shell`"):
|
30
|
+
GnuParallelLocalAdapter(
|
31
|
+
job_name="check_env_shell",
|
32
|
+
job_dir=Path("."),
|
33
|
+
yaml_config_path=Path("."),
|
34
|
+
elements=["sub01"],
|
35
|
+
env={"kind": "conda", "shell": "fish"},
|
36
|
+
)
|
37
|
+
|
38
|
+
|
27
39
|
@pytest.mark.parametrize(
|
28
40
|
"elements, expected_text",
|
29
41
|
[
|
@@ -55,14 +67,18 @@ def test_GnuParallelLocalAdapter_elements(
|
|
55
67
|
|
56
68
|
|
57
69
|
@pytest.mark.parametrize(
|
58
|
-
"pre_run, expected_text",
|
70
|
+
"pre_run, expected_text, shell",
|
59
71
|
[
|
60
|
-
(None, "# Force datalad"),
|
61
|
-
("#
|
72
|
+
(None, "# Force datalad", "bash"),
|
73
|
+
(None, "# Force datalad", "zsh"),
|
74
|
+
("# Check this out\n", "# Check this out", "bash"),
|
75
|
+
("# Check this out\n", "# Check this out", "zsh"),
|
62
76
|
],
|
63
77
|
)
|
64
78
|
def test_GnuParallelLocalAdapter_pre_run(
|
65
|
-
pre_run: Optional[str],
|
79
|
+
pre_run: Optional[str],
|
80
|
+
expected_text: str,
|
81
|
+
shell: str,
|
66
82
|
) -> None:
|
67
83
|
"""Test GnuParallelLocalAdapter pre_run().
|
68
84
|
|
@@ -72,6 +88,8 @@ def test_GnuParallelLocalAdapter_pre_run(
|
|
72
88
|
The parametrized pre run text.
|
73
89
|
expected_text : str
|
74
90
|
The parametrized expected text.
|
91
|
+
shell : str
|
92
|
+
The parametrized expected shell.
|
75
93
|
|
76
94
|
"""
|
77
95
|
adapter = GnuParallelLocalAdapter(
|
@@ -79,21 +97,26 @@ def test_GnuParallelLocalAdapter_pre_run(
|
|
79
97
|
job_dir=Path("."),
|
80
98
|
yaml_config_path=Path("."),
|
81
99
|
elements=["sub01"],
|
100
|
+
env={"kind": "conda", "name": "junifer", "shell": shell},
|
82
101
|
pre_run=pre_run,
|
83
102
|
)
|
103
|
+
assert shell in adapter.pre_run()
|
84
104
|
assert expected_text in adapter.pre_run()
|
85
105
|
|
86
106
|
|
87
107
|
@pytest.mark.parametrize(
|
88
|
-
"pre_collect, expected_text",
|
108
|
+
"pre_collect, expected_text, shell",
|
89
109
|
[
|
90
|
-
(None, "# This script"),
|
91
|
-
("#
|
110
|
+
(None, "# This script", "bash"),
|
111
|
+
(None, "# This script", "zsh"),
|
112
|
+
("# Check this out\n", "# Check this out", "bash"),
|
113
|
+
("# Check this out\n", "# Check this out", "zsh"),
|
92
114
|
],
|
93
115
|
)
|
94
116
|
def test_GnuParallelLocalAdapter_pre_collect(
|
95
117
|
pre_collect: Optional[str],
|
96
118
|
expected_text: str,
|
119
|
+
shell: str,
|
97
120
|
) -> None:
|
98
121
|
"""Test GnuParallelLocalAdapter pre_collect().
|
99
122
|
|
@@ -103,6 +126,8 @@ def test_GnuParallelLocalAdapter_pre_collect(
|
|
103
126
|
The parametrized pre collect text.
|
104
127
|
expected_text : str
|
105
128
|
The parametrized expected text.
|
129
|
+
shell : str
|
130
|
+
The parametrized expected shell.
|
106
131
|
|
107
132
|
"""
|
108
133
|
adapter = GnuParallelLocalAdapter(
|
@@ -110,8 +135,10 @@ def test_GnuParallelLocalAdapter_pre_collect(
|
|
110
135
|
job_dir=Path("."),
|
111
136
|
yaml_config_path=Path("."),
|
112
137
|
elements=["sub01"],
|
138
|
+
env={"kind": "venv", "name": "junifer", "shell": shell},
|
113
139
|
pre_collect=pre_collect,
|
114
140
|
)
|
141
|
+
assert shell in adapter.pre_collect()
|
115
142
|
assert expected_text in adapter.pre_collect()
|
116
143
|
|
117
144
|
|
@@ -140,8 +167,10 @@ def test_GnuParallelLocalAdapter_collect() -> None:
|
|
140
167
|
@pytest.mark.parametrize(
|
141
168
|
"env",
|
142
169
|
[
|
143
|
-
{"kind": "conda", "name": "junifer"},
|
144
|
-
{"kind": "
|
170
|
+
{"kind": "conda", "name": "junifer", "shell": "bash"},
|
171
|
+
{"kind": "conda", "name": "junifer", "shell": "zsh"},
|
172
|
+
{"kind": "venv", "name": "./junifer", "shell": "bash"},
|
173
|
+
{"kind": "venv", "name": "./junifer", "shell": "zsh"},
|
145
174
|
],
|
146
175
|
)
|
147
176
|
def test_GnuParallelLocalAdapter_prepare(
|
@@ -177,7 +206,7 @@ def test_GnuParallelLocalAdapter_prepare(
|
|
177
206
|
adapter.prepare()
|
178
207
|
|
179
208
|
assert "GNU parallel" in caplog.text
|
180
|
-
assert f"Copying run_{env['kind']}" in caplog.text
|
209
|
+
assert f"Copying run_{env['kind']}.{env['shell']}" in caplog.text
|
181
210
|
assert "Writing pre_run.sh" in caplog.text
|
182
211
|
assert "Writing run_test_prepare.sh" in caplog.text
|
183
212
|
assert "Writing pre_collect.sh" in caplog.text
|