diff --git a/cubids/cli.py b/cubids/cli.py index 6fde0885..5ea72db9 100644 --- a/cubids/cli.py +++ b/cubids/cli.py @@ -67,12 +67,6 @@ def _parse_validate(): help="Run the BIDS validator sequentially on each subject.", required=False, ) - parser.add_argument( - "--container", - action="store", - help="Docker image tag or Singularity image file.", - default=None, - ) parser.add_argument( "--ignore_nifti_headers", action="store_true", @@ -171,11 +165,6 @@ def _parse_group(): "then output files will go to the specified location." ), ) - parser.add_argument( - "--container", - action="store", - help="Docker image tag or Singularity image file.", - ) parser.add_argument( "--acq-group-level", default="subject", @@ -267,11 +256,6 @@ def _parse_apply(): default=False, help="ensure that there are no untracked changes before finding groups", ) - parser.add_argument( - "--container", - action="store", - help="Docker image tag or Singularity image file.", - ) parser.add_argument( "--acq-group-level", default="subject", @@ -325,11 +309,6 @@ def _parse_datalad_save(): action="store", help="message for this commit", ) - parser.add_argument( - "--container", - action="store", - help="Docker image tag or Singularity image file.", - ) return parser @@ -362,11 +341,6 @@ def _parse_undo(): "sub-X directories and dataset_description.json" ), ) - parser.add_argument( - "--container", - action="store", - help="Docker image tag or Singularity image file.", - ) return parser @@ -449,11 +423,6 @@ def _parse_copy_exemplars(): # help='only include an exemplar subject from these ' # 'listed Acquisition Groups in the exemplar dataset ', # required=False) - parser.add_argument( - "--container", - action="store", - help="Docker image tag or Singularity image file.", - ) return parser @@ -501,11 +470,6 @@ def _parse_add_nifti_info(): default=False, help="unlock dataset before adding nifti info ", ) - parser.add_argument( - "--container", - action="store", - help="Docker image tag or Singularity image file.", - ) return parser @@ -551,11 +515,6 @@ def _parse_purge(): default=False, help="ensure that there are no untracked changes before finding groups", ) - parser.add_argument( - "--container", - action="store", - help="Docker image tag or Singularity image file.", - ) return parser @@ -593,12 +552,6 @@ def _parse_remove_metadata_fields(): default=[], help="space-separated list of metadata fields to remove.", ) - parser.add_argument( - "--container", - action="store", - help="Docker image tag or Singularity image file.", - ) - return parser @@ -632,12 +585,6 @@ def _parse_print_metadata_fields(): "sub-X directories and dataset_description.json" ), ) - parser.add_argument( - "--container", - action="store", - help="Docker image tag or Singularity image file.", - ) - return parser diff --git a/cubids/tests/test_bond.py b/cubids/tests/test_bond.py index 867f22cd..9e38b458 100644 --- a/cubids/tests/test_bond.py +++ b/cubids/tests/test_bond.py @@ -1028,31 +1028,6 @@ def test_validator(tmp_path): assert isinstance(parsed, pd.DataFrame) -def test_docker(): - """Verify that docker is installed and the user has permission to run docker images. - - Returns - ------- - -1 Docker can't be found - 0 Docker found, but user can't connect to daemon - 1 Test run OK - """ - try: - return_status = 1 - ret = subprocess.run(["docker", "version"], stdout=subprocess.PIPE, stderr=subprocess.PIPE) - except OSError as e: - from errno import ENOENT - - if e.errno == ENOENT: - print("Cannot find Docker engine!") - return_status = 0 - raise e - if ret.stderr.startswith(b"Cannot connect to the Docker daemon."): - print("Cannot connect to Docker daemon!") - return_status = 0 - assert return_status - - # def test_image(image='pennlinc/bond:latest'): # """Check whether image is present on local system.""" # ret = subprocess.run(['docker', 'images', '-q', image], diff --git a/cubids/utils.py b/cubids/utils.py deleted file mode 100644 index 09c02e34..00000000 --- a/cubids/utils.py +++ /dev/null @@ -1,33 +0,0 @@ -"""Miscellaneous utility functions for CuBIDS.""" - -import re -from pathlib import Path - - -def _get_container_type(image_name): - """Get and return the container type. - - Parameters - ---------- - image_name : :obj:`str` - The name of the container image. - - Returns - ------- - :obj:`str` - The container type, either "docker" or "singularity". - - Raises - ------ - :obj:`Exception` - If the container type cannot be determined. - """ - # If it's a file on disk, it must be a singularity image - if Path(image_name).exists(): - return "singularity" - - # It needs to match a docker tag pattern to be docker - if re.match(r"(?:.+\/)?([^:]+)(?::.+)?", image_name): - return "docker" - - raise Exception("Unable to determine the container type of " + image_name) diff --git a/cubids/validator.py b/cubids/validator.py index 01dad11c..5e0fedfe 100644 --- a/cubids/validator.py +++ b/cubids/validator.py @@ -14,7 +14,6 @@ def build_validator_call(path, ignore_headers=False): """Build a subprocess command to the bids validator.""" - # build docker call # CuBIDS automatically ignores subject consistency. command = ["bids-validator", "--verbose", "--json", "--ignoreSubjectConsistency"] diff --git a/cubids/workflows.py b/cubids/workflows.py index 307be51b..a47757c6 100644 --- a/cubids/workflows.py +++ b/cubids/workflows.py @@ -15,7 +15,6 @@ from cubids.cubids import CuBIDS from cubids.metadata_merge import merge_json_into_json -from cubids.utils import _get_container_type from cubids.validator import ( build_subject_paths, build_validator_call, @@ -34,7 +33,6 @@ def validate( bids_dir, output_prefix, - container, sequential, sequential_subjects, ignore_nifti_headers, @@ -47,8 +45,6 @@ def validate( Path to the BIDS directory. output_prefix : :obj:`pathlib.Path` Output filename prefix. - container : :obj:`str` - Container in which to run the workflow. sequential : :obj:`bool` Run the validator sequentially. sequential_subjects : :obj:`list` of :obj:`str` @@ -68,194 +64,131 @@ def validate( subprocess.run(["mkdir", str(bids_dir / "code" / "CuBIDS")]) # Run directly from python using subprocess - if container is None: - if not sequential: - # run on full dataset - call = build_validator_call( - str(bids_dir), - ignore_nifti_headers, - ) - ret = run_validator(call) + if not sequential: + # run on full dataset + call = build_validator_call( + str(bids_dir), + ignore_nifti_headers, + ) + ret = run_validator(call) - # parse the string output - parsed = parse_validator_output(ret.stdout.decode("UTF-8")) - if parsed.shape[1] < 1: - logger.info("No issues/warnings parsed, your dataset is BIDS valid.") - sys.exit(0) - else: - logger.info("BIDS issues/warnings found in the dataset") + # parse the string output + parsed = parse_validator_output(ret.stdout.decode("UTF-8")) + if parsed.shape[1] < 1: + logger.info("No issues/warnings parsed, your dataset is BIDS valid.") + sys.exit(0) + else: + logger.info("BIDS issues/warnings found in the dataset") - if output_prefix: - # check if absolute or relative path - if abs_path_output: - # normally, write dataframe to file in CLI - val_tsv = str(output_prefix) + "_validation.tsv" + if output_prefix: + # check if absolute or relative path + if abs_path_output: + # normally, write dataframe to file in CLI + val_tsv = str(output_prefix) + "_validation.tsv" - else: - val_tsv = ( - str(bids_dir) - + "/code/CuBIDS/" - + str(output_prefix) - + "_validation.tsv" - ) - - parsed.to_csv(val_tsv, sep="\t", index=False) - - # build validation data dictionary json sidecar - val_dict = get_val_dictionary() - val_json = val_tsv.replace("tsv", "json") - with open(val_json, "w") as outfile: - json.dump(val_dict, outfile, indent=4) - - logger.info("Writing issues out to %s", val_tsv) - sys.exit(0) else: - # user may be in python session, return dataframe - return parsed - else: - # logger.info("Prepping sequential validator run...") - - # build a dictionary with {SubjectLabel: [List of files]} - subjects_dict = build_subject_paths(bids_dir) - - # logger.info("Running validator sequentially...") - # iterate over the dictionary - - parsed = [] - - if sequential_subjects: - subjects_dict = { - k: v for k, v in subjects_dict.items() if k in sequential_subjects - } - assert len(list(subjects_dict.keys())) > 1, "No subjects found in filter" - for subject, files_list in tqdm.tqdm(subjects_dict.items()): - # logger.info(" ".join(["Processing subject:", subject])) - # create a temporary directory and symlink the data - with tempfile.TemporaryDirectory() as tmpdirname: - for fi in files_list: - # cut the path down to the subject label - bids_start = fi.find(subject) - - # maybe it's a single file - if bids_start < 1: - bids_folder = tmpdirname - fi_tmpdir = tmpdirname - - else: - bids_folder = Path(fi[bids_start:]).parent - fi_tmpdir = tmpdirname + "/" + str(bids_folder) - - if not os.path.exists(fi_tmpdir): - os.makedirs(fi_tmpdir) - output = fi_tmpdir + "/" + str(Path(fi).name) - shutil.copy2(fi, output) - - # run the validator - nifti_head = ignore_nifti_headers - call = build_validator_call(tmpdirname, nifti_head) - ret = run_validator(call) - # parse output - if ret.returncode != 0: - logger.error("Errors returned from validator run, parsing now") - - # parse the output and add to list if it returns a df - decoded = ret.stdout.decode("UTF-8") - tmp_parse = parse_validator_output(decoded) - if tmp_parse.shape[1] > 1: - tmp_parse["subject"] = subject - parsed.append(tmp_parse) - - # concatenate the parsed data and exit - if len(parsed) < 1: - logger.info("No issues/warnings parsed, your dataset is BIDS valid.") - sys.exit(0) + val_tsv = ( + str(bids_dir) + "/code/CuBIDS/" + str(output_prefix) + "_validation.tsv" + ) - else: - parsed = pd.concat(parsed, axis=0) - subset = parsed.columns.difference(["subject"]) - parsed = parsed.drop_duplicates(subset=subset) + parsed.to_csv(val_tsv, sep="\t", index=False) - logger.info("BIDS issues/warnings found in the dataset") + # build validation data dictionary json sidecar + val_dict = get_val_dictionary() + val_json = val_tsv.replace("tsv", "json") + with open(val_json, "w") as outfile: + json.dump(val_dict, outfile, indent=4) + + logger.info("Writing issues out to %s", val_tsv) + sys.exit(0) + else: + # user may be in python session, return dataframe + return parsed + else: + # logger.info("Prepping sequential validator run...") + + # build a dictionary with {SubjectLabel: [List of files]} + subjects_dict = build_subject_paths(bids_dir) + + # logger.info("Running validator sequentially...") + # iterate over the dictionary + + parsed = [] + + if sequential_subjects: + subjects_dict = {k: v for k, v in subjects_dict.items() if k in sequential_subjects} + assert len(list(subjects_dict.keys())) > 1, "No subjects found in filter" + for subject, files_list in tqdm.tqdm(subjects_dict.items()): + # logger.info(" ".join(["Processing subject:", subject])) + # create a temporary directory and symlink the data + with tempfile.TemporaryDirectory() as tmpdirname: + for fi in files_list: + # cut the path down to the subject label + bids_start = fi.find(subject) + + # maybe it's a single file + if bids_start < 1: + bids_folder = tmpdirname + fi_tmpdir = tmpdirname - if output_prefix: - # normally, write dataframe to file in CLI - if abs_path_output: - val_tsv = str(output_prefix) + "_validation.tsv" else: - val_tsv = ( - str(bids_dir) - + "/code/CuBIDS/" - + str(output_prefix) - + "_validation.tsv" - ) - - parsed.to_csv(val_tsv, sep="\t", index=False) - - # build validation data dictionary json sidecar - val_dict = get_val_dictionary() - val_json = val_tsv.replace("tsv", "json") - with open(val_json, "w") as outfile: - json.dump(val_dict, outfile, indent=4) - - logger.info("Writing issues out to file %s", val_tsv) - sys.exit(0) + bids_folder = Path(fi[bids_start:]).parent + fi_tmpdir = tmpdirname + "/" + str(bids_folder) + + if not os.path.exists(fi_tmpdir): + os.makedirs(fi_tmpdir) + output = fi_tmpdir + "/" + str(Path(fi).name) + shutil.copy2(fi, output) + + # run the validator + nifti_head = ignore_nifti_headers + call = build_validator_call(tmpdirname, nifti_head) + ret = run_validator(call) + # parse output + if ret.returncode != 0: + logger.error("Errors returned from validator run, parsing now") + + # parse the output and add to list if it returns a df + decoded = ret.stdout.decode("UTF-8") + tmp_parse = parse_validator_output(decoded) + if tmp_parse.shape[1] > 1: + tmp_parse["subject"] = subject + parsed.append(tmp_parse) + + # concatenate the parsed data and exit + if len(parsed) < 1: + logger.info("No issues/warnings parsed, your dataset is BIDS valid.") + sys.exit(0) + + else: + parsed = pd.concat(parsed, axis=0) + subset = parsed.columns.difference(["subject"]) + parsed = parsed.drop_duplicates(subset=subset) + + logger.info("BIDS issues/warnings found in the dataset") + + if output_prefix: + # normally, write dataframe to file in CLI + if abs_path_output: + val_tsv = str(output_prefix) + "_validation.tsv" else: - # user may be in python session, return dataframe - return parsed - - # Run it through a container - container_type = _get_container_type(container) - bids_dir_link = str(bids_dir.absolute()) + ":/bids:ro" - output_dir_link_t = str(output_prefix.parent.absolute()) + ":/tsv:rw" - output_dir_link_j = str(output_prefix.parent.absolute()) + ":/json:rw" - linked_output_prefix_t = "/tsv/" + output_prefix.name - if container_type == "docker": - cmd = [ - "docker", - "run", - "--rm", - "-v", - bids_dir_link, - "-v", - GIT_CONFIG + ":/root/.gitconfig", - "-v", - output_dir_link_t, - "-v", - output_dir_link_j, - "--entrypoint", - "cubids-validate", - container, - "/bids", - linked_output_prefix_t, - ] - if ignore_nifti_headers: - cmd.append("--ignore_nifti_headers") - - elif container_type == "singularity": - cmd = [ - "singularity", - "exec", - "--cleanenv", - "-B", - bids_dir_link, - "-B", - output_dir_link_t, - "-B", - output_dir_link_j, - container, - "cubids-validate", - "/bids", - linked_output_prefix_t, - ] - if ignore_nifti_headers: - cmd.append("--ignore_nifti_headers") - - if sequential: - cmd.append("--sequential") - - logger.info("RUNNING: " + " ".join(cmd)) - proc = subprocess.run(cmd) - sys.exit(proc.returncode) + val_tsv = ( + str(bids_dir) + "/code/CuBIDS/" + str(output_prefix) + "_validation.tsv" + ) + + parsed.to_csv(val_tsv, sep="\t", index=False) + + # build validation data dictionary json sidecar + val_dict = get_val_dictionary() + val_json = val_tsv.replace("tsv", "json") + with open(val_json, "w") as outfile: + json.dump(val_dict, outfile, indent=4) + + logger.info("Writing issues out to file %s", val_tsv) + sys.exit(0) + else: + # user may be in python session, return dataframe + return parsed def bids_sidecar_merge(from_json, to_json): @@ -264,15 +197,13 @@ def bids_sidecar_merge(from_json, to_json): sys.exit(merge_status) -def group(bids_dir, container, acq_group_level, config, output_prefix): +def group(bids_dir, acq_group_level, config, output_prefix): """Find key and param groups. Parameters ---------- bids_dir : :obj:`pathlib.Path` Path to the BIDS directory. - container : :obj:`str` - Container in which to run the workflow. acq_group_level : {"subject", "session"} Level at which acquisition groups are created. config : :obj:`pathlib.Path` @@ -281,76 +212,15 @@ def group(bids_dir, container, acq_group_level, config, output_prefix): Output filename prefix. """ # Run directly from python using - if container is None: - bod = CuBIDS( - data_root=str(bids_dir), - acq_group_level=acq_group_level, - grouping_config=config, - ) - bod.get_tsvs( - str(output_prefix), - ) - sys.exit(0) - - # Run it through a container - container_type = _get_container_type(container) - bids_dir_link = str(bids_dir.absolute()) + ":/bids" - output_dir_link = str(output_prefix.parent.absolute()) + ":/tsv:rw" - - apply_config = config is not None - if apply_config: - input_config_dir_link = str(config.parent.absolute()) + ":/in_config:ro" - linked_input_config = "/in_config/" + config.name - - linked_output_prefix = "/tsv/" + output_prefix.name - if container_type == "docker": - cmd = [ - "docker", - "run", - "--rm", - "-v", - bids_dir_link, - "-v", - GIT_CONFIG + ":/root/.gitconfig", - "-v", - output_dir_link, - "--entrypoint", - "cubids-group", - container, - "/bids", - linked_output_prefix, - ] - if apply_config: - cmd.insert(3, "-v") - cmd.insert(4, input_config_dir_link) - cmd += ["--config", linked_input_config] - - elif container_type == "singularity": - cmd = [ - "singularity", - "exec", - "--cleanenv", - "-B", - bids_dir_link, - "-B", - output_dir_link, - container, - "cubids-group", - "/bids", - linked_output_prefix, - ] - if apply_config: - cmd.insert(3, "-B") - cmd.insert(4, input_config_dir_link) - cmd += ["--config", linked_input_config] - - if acq_group_level: - cmd.append("--acq-group-level") - cmd.append(str(acq_group_level)) - - logger.info("RUNNING: " + " ".join(cmd)) - proc = subprocess.run(cmd) - sys.exit(proc.returncode) + bod = CuBIDS( + data_root=str(bids_dir), + acq_group_level=acq_group_level, + grouping_config=config, + ) + bod.get_tsvs( + str(output_prefix), + ) + sys.exit(0) def apply( @@ -359,11 +229,8 @@ def apply( acq_group_level, config, edited_summary_tsv, - edited_tsv_prefix, files_tsv, new_tsv_prefix, - output_prefix, - container, ): """Apply the tsv changes. @@ -379,232 +246,66 @@ def apply( Path to the grouping config file. edited_summary_tsv : :obj:`pathlib.Path` Path to the edited summary tsv. - edited_tsv_prefix : :obj:`pathlib.Path` - Path to the edited tsv prefix. files_tsv : :obj:`pathlib.Path` Path to the files tsv. new_tsv_prefix : :obj:`pathlib.Path` Path to the new tsv prefix. - output_prefix : :obj:`pathlib.Path` - Output filename prefix. - container : :obj:`str` - Container in which to run the workflow. """ # Run directly from python using - if container is None: - bod = CuBIDS( - data_root=str(bids_dir), - use_datalad=use_datalad, - acq_group_level=acq_group_level, - grouping_config=config, - ) - if use_datalad: - if not bod.is_datalad_clean(): - raise Exception("Untracked change in " + str(bids_dir)) - bod.apply_tsv_changes( - str(edited_summary_tsv), - str(files_tsv), - str(new_tsv_prefix), - raise_on_error=False, - ) - sys.exit(0) - - # Run it through a container - container_type = _get_container_type(container) - bids_dir_link = str(bids_dir.absolute()) + ":/bids" - input_summary_tsv_dir_link = str(edited_tsv_prefix.parent.absolute()) + ":/in_summary_tsv:ro" - input_files_tsv_dir_link = str(edited_tsv_prefix.parent.absolute()) + ":/in_files_tsv:ro" - output_tsv_dir_link = str(new_tsv_prefix.parent.absolute()) + ":/out_tsv:rw" - - # FROM BOND-GROUP - apply_config = config is not None - if apply_config: - input_config_dir_link = str(config.parent.absolute()) + ":/in_config:ro" - linked_input_config = "/in_config/" + config.name - - linked_output_prefix = "/tsv/" + output_prefix.name - - #### - linked_input_summary_tsv = "/in_summary_tsv/" + edited_summary_tsv.name - linked_input_files_tsv = "/in_files_tsv/" + files_tsv.name - linked_output_prefix = "/out_tsv/" + new_tsv_prefix.name - if container_type == "docker": - cmd = [ - "docker", - "run", - "--rm", - "-v", - bids_dir_link, - "-v", - GIT_CONFIG + ":/root/.gitconfig", - "-v", - input_summary_tsv_dir_link, - "-v", - input_files_tsv_dir_link, - "-v", - output_tsv_dir_link, - "--entrypoint", - "cubids-apply", - container, - "/bids", - linked_input_summary_tsv, - linked_input_files_tsv, - linked_output_prefix, - ] - if apply_config: - cmd.insert(3, "-v") - cmd.insert(4, input_config_dir_link) - cmd += ["--config", linked_input_config] - - elif container_type == "singularity": - cmd = [ - "singularity", - "exec", - "--cleanenv", - "-B", - bids_dir_link, - "-B", - input_summary_tsv_dir_link, - "-B", - input_files_tsv_dir_link, - "-B", - output_tsv_dir_link, - container, - "cubids-apply", - "/bids", - linked_input_summary_tsv, - linked_input_files_tsv, - linked_output_prefix, - ] - if apply_config: - cmd.insert(3, "-B") - cmd.insert(4, input_config_dir_link) - cmd += ["--config", linked_input_config] - + bod = CuBIDS( + data_root=str(bids_dir), + use_datalad=use_datalad, + acq_group_level=acq_group_level, + grouping_config=config, + ) if use_datalad: - cmd.append("--use-datalad") - - if acq_group_level: - cmd.append("--acq-group-level") - cmd.append(str(acq_group_level)) - - logger.info("RUNNING: " + " ".join(cmd)) - proc = subprocess.run(cmd) - sys.exit(proc.returncode) - - -def datalad_save(bids_dir, container, m): + if not bod.is_datalad_clean(): + raise Exception("Untracked change in " + str(bids_dir)) + bod.apply_tsv_changes( + str(edited_summary_tsv), + str(files_tsv), + str(new_tsv_prefix), + raise_on_error=False, + ) + sys.exit(0) + + +def datalad_save(bids_dir, m): """Perform datalad save. Parameters ---------- bids_dir : :obj:`pathlib.Path` Path to the BIDS directory. - container : :obj:`str` - Container in which to run the workflow. m : :obj:`str` Commit message. """ # Run directly from python using - if container is None: - bod = CuBIDS(data_root=str(bids_dir), use_datalad=True) - bod.datalad_save(message=m) - sys.exit(0) - - # Run it through a container - container_type = _get_container_type(container) - bids_dir_link = str(bids_dir.absolute()) + ":/bids" - if container_type == "docker": - cmd = [ - "docker", - "run", - "--rm", - "-v", - bids_dir_link, - "-v", - GIT_CONFIG + ":/root/.gitconfig", - "--entrypoint", - "cubids-datalad-save", - container, - "/bids", - "-m", - m, - ] - elif container_type == "singularity": - cmd = [ - "singularity", - "exec", - "--cleanenv", - "-B", - bids_dir_link, - container, - "cubids-datalad-save", - "/bids", - "-m", - m, - ] - logger.info("RUNNING: " + " ".join(cmd)) - proc = subprocess.run(cmd) - sys.exit(proc.returncode) - - -def undo(bids_dir, container): + bod = CuBIDS(data_root=str(bids_dir), use_datalad=True) + bod.datalad_save(message=m) + sys.exit(0) + + +def undo(bids_dir): """Revert the most recent commit. Parameters ---------- bids_dir : :obj:`pathlib.Path` Path to the BIDS directory. - container : :obj:`str` - Container in which to run the workflow. """ # Run directly from python using - if container is None: - bod = CuBIDS(data_root=str(bids_dir), use_datalad=True) - bod.datalad_undo_last_commit() - sys.exit(0) - - # Run it through a container - container_type = _get_container_type(container) - bids_dir_link = str(bids_dir.absolute()) + ":/bids" - if container_type == "docker": - cmd = [ - "docker", - "run", - "--rm", - "-v", - bids_dir_link, - "-v", - GIT_CONFIG + ":/root/.gitconfig", - "--entrypoint", - "cubids-undo", - container, - "/bids", - ] - elif container_type == "singularity": - cmd = [ - "singularity", - "exec", - "--cleanenv", - "-B", - bids_dir_link, - container, - "cubids-undo", - "/bids", - ] - logger.info("RUNNING: " + " ".join(cmd)) - proc = subprocess.run(cmd) - sys.exit(proc.returncode) + bod = CuBIDS(data_root=str(bids_dir), use_datalad=True) + bod.datalad_undo_last_commit() + sys.exit(0) def copy_exemplars( bids_dir, - container, use_datalad, exemplars_dir, exemplars_tsv, min_group_size, - force_unlock, ): """Create and save a directory with one subject from each acquisition group. @@ -612,8 +313,6 @@ def copy_exemplars( ---------- bids_dir : :obj:`pathlib.Path` Path to the BIDS directory. - container : :obj:`str` - Container in which to run the workflow. use_datalad : :obj:`bool` Use datalad to track changes. exemplars_dir : :obj:`pathlib.Path` @@ -622,314 +321,96 @@ def copy_exemplars( Path to the tsv file with the exemplars. min_group_size : :obj:`int` Minimum number of subjects in a group to be considered for exemplar. - force_unlock : :obj:`bool` - Force unlock the dataset. """ # Run directly from python using - if container is None: - bod = CuBIDS(data_root=str(bids_dir), use_datalad=use_datalad) - if use_datalad: - if not bod.is_datalad_clean(): - raise Exception( - "Untracked changes. Need to save " - + str(bids_dir) - + " before coyping exemplars" - ) - bod.copy_exemplars( - str(exemplars_dir), - str(exemplars_tsv), - min_group_size=min_group_size, - ) - sys.exit(0) - - # Run it through a container - container_type = _get_container_type(container) - bids_dir_link = str(bids_dir.absolute()) + ":/bids:ro" - exemplars_dir_link = str(exemplars_dir.absolute()) + ":/exemplars:ro" - exemplars_tsv_link = str(exemplars_tsv.absolute()) + ":/in_tsv:ro" - if container_type == "docker": - cmd = [ - "docker", - "run", - "--rm", - "-v", - bids_dir_link, - "-v", - exemplars_dir_link, - "-v", - GIT_CONFIG + ":/root/.gitconfig", - "-v", - exemplars_tsv_link, - "--entrypoint", - "cubids-copy-exemplars", - container, - "/bids", - "/exemplars", - "/in_tsv", - ] - - if force_unlock: - cmd.append("--force-unlock") - - if min_group_size: - cmd.append("--min-group-size") - - elif container_type == "singularity": - cmd = [ - "singularity", - "exec", - "--cleanenv", - "-B", - bids_dir_link, - "-B", - exemplars_dir_link, - "-B", - exemplars_tsv_link, - container, - "cubids-copy-exemplars", - "/bids", - "/exemplars", - "/in_tsv", - ] - if force_unlock: - cmd.append("--force-unlock") - - if min_group_size: - cmd.append("--min-group-size") - - logger.info("RUNNING: " + " ".join(cmd)) - proc = subprocess.run(cmd) - sys.exit(proc.returncode) - - -def add_nifti_info(bids_dir, container, use_datalad, force_unlock): + bod = CuBIDS(data_root=str(bids_dir), use_datalad=use_datalad) + if use_datalad: + if not bod.is_datalad_clean(): + raise Exception( + "Untracked changes. Need to save " + str(bids_dir) + " before coyping exemplars" + ) + bod.copy_exemplars( + str(exemplars_dir), + str(exemplars_tsv), + min_group_size=min_group_size, + ) + sys.exit(0) + + +def add_nifti_info(bids_dir, use_datalad, force_unlock): """Add information from nifti files to the dataset's sidecars. Parameters ---------- bids_dir : :obj:`pathlib.Path` Path to the BIDS directory. - container : :obj:`str` - Container in which to run the workflow. use_datalad : :obj:`bool` Use datalad to track changes. force_unlock : :obj:`bool` Force unlock the dataset. """ # Run directly from python using - if container is None: - bod = CuBIDS( - data_root=str(bids_dir), - use_datalad=use_datalad, - force_unlock=force_unlock, - ) - if use_datalad: - if not bod.is_datalad_clean(): - raise Exception("Untracked change in " + str(bids_dir)) - # if bod.is_datalad_clean() and not force_unlock: - # raise Exception("Need to unlock " + str(bids_dir)) - bod.add_nifti_info() - sys.exit(0) - - # Run it through a container - container_type = _get_container_type(container) - bids_dir_link = str(bids_dir.absolute()) + ":/bids:ro" - if container_type == "docker": - cmd = [ - "docker", - "run", - "--rm", - "-v", - bids_dir_link, - "-v", - GIT_CONFIG + ":/root/.gitconfig", - "--entrypoint", - "cubids-add-nifti-info", - container, - "/bids", - ] - - if force_unlock: - cmd.append("--force-unlock") - elif container_type == "singularity": - cmd = [ - "singularity", - "exec", - "--cleanenv", - "-B", - bids_dir_link, - container, - "cubids-add-nifti-info", - "/bids", - ] - if force_unlock: - cmd.append("--force-unlock") - - logger.info("RUNNING: " + " ".join(cmd)) - proc = subprocess.run(cmd) - sys.exit(proc.returncode) - - -def purge(bids_dir, container, use_datalad, scans): + bod = CuBIDS( + data_root=str(bids_dir), + use_datalad=use_datalad, + force_unlock=force_unlock, + ) + if use_datalad: + if not bod.is_datalad_clean(): + raise Exception("Untracked change in " + str(bids_dir)) + # if bod.is_datalad_clean() and not force_unlock: + # raise Exception("Need to unlock " + str(bids_dir)) + bod.add_nifti_info() + sys.exit(0) + + +def purge(bids_dir, use_datalad, scans): """Purge scan associations. Parameters ---------- bids_dir : :obj:`pathlib.Path` Path to the BIDS directory. - container : :obj:`str` - Container in which to run the workflow. use_datalad : :obj:`bool` Use datalad to track changes. scans : :obj:`pathlib.Path` Path to the scans tsv. """ # Run directly from python using - if container is None: - bod = CuBIDS(data_root=str(bids_dir), use_datalad=use_datalad) - if use_datalad: - if not bod.is_datalad_clean(): - raise Exception("Untracked change in " + str(bids_dir)) - bod.purge(str(scans)) - sys.exit(0) - - # Run it through a container - container_type = _get_container_type(container) - bids_dir_link = str(bids_dir.absolute()) + ":/bids" - input_scans_link = str(scans.parent.absolute()) + ":/in_scans:ro" - if container_type == "docker": - cmd = [ - "docker", - "run", - "--rm", - "-v", - bids_dir_link, - "-v", - GIT_CONFIG + ":/root/.gitconfig", - "-v", - input_scans_link, - "--entrypoint", - "cubids-purge", - container, - "/bids", - input_scans_link, - ] - - elif container_type == "singularity": - cmd = [ - "singularity", - "exec", - "--cleanenv", - "-B", - bids_dir_link, - "-B", - input_scans_link, - container, - "cubids-purge", - "/bids", - input_scans_link, - ] - logger.info("RUNNING: " + " ".join(cmd)) + bod = CuBIDS(data_root=str(bids_dir), use_datalad=use_datalad) if use_datalad: - cmd.append("--use-datalad") - proc = subprocess.run(cmd) - sys.exit(proc.returncode) + if not bod.is_datalad_clean(): + raise Exception("Untracked change in " + str(bids_dir)) + bod.purge(str(scans)) + sys.exit(0) -def remove_metadata_fields(bids_dir, container, fields): +def remove_metadata_fields(bids_dir, fields): """Delete fields from metadata. Parameters ---------- bids_dir : :obj:`pathlib.Path` Path to the BIDS directory. - container : :obj:`str` - Container in which to run the workflow. fields : :obj:`list` of :obj:`str` List of fields to remove. """ # Run directly from python - if container is None: - bod = CuBIDS(data_root=str(bids_dir), use_datalad=False) - bod.remove_metadata_fields(fields) - sys.exit(0) - - # Run it through a container - container_type = _get_container_type(container) - bids_dir_link = str(bids_dir.absolute()) + ":/bids:rw" - if container_type == "docker": - cmd = [ - "docker", - "run", - "--rm", - "-v", - bids_dir_link, - "--entrypoint", - "cubids-remove-metadata-fields", - container, - "/bids", - "--fields", - ] + fields - elif container_type == "singularity": - cmd = [ - "singularity", - "exec", - "--cleanenv", - "-B", - bids_dir_link, - container, - "cubids-remove-metadata-fields", - "/bids", - "--fields", - ] + fields - logger.info("RUNNING: " + " ".join(cmd)) - proc = subprocess.run(cmd) - sys.exit(proc.returncode) - - -def print_metadata_fields(bids_dir, container): + bod = CuBIDS(data_root=str(bids_dir), use_datalad=False) + bod.remove_metadata_fields(fields) + sys.exit(0) + + +def print_metadata_fields(bids_dir): """Print unique metadata fields. Parameters ---------- bids_dir : :obj:`pathlib.Path` Path to the BIDS directory. - container : :obj:`str` - Container in which to run the workflow. """ # Run directly from python - if container is None: - bod = CuBIDS(data_root=str(bids_dir), use_datalad=False) - fields = bod.get_all_metadata_fields() - logger.info("\n".join(fields)) - sys.exit(0) - - # Run it through a container - container_type = _get_container_type(container) - bids_dir_link = str(bids_dir.absolute()) + ":/bids:ro" - if container_type == "docker": - cmd = [ - "docker", - "run", - "--rm", - "-v", - bids_dir_link, - "--entrypoint", - "cubids-print-metadata-fields", - container, - "/bids", - ] - elif container_type == "singularity": - cmd = [ - "singularity", - "exec", - "--cleanenv", - "-B", - bids_dir_link, - container, - "cubids-print-metadata-fields", - "/bids", - ] - logger.info("RUNNING: " + " ".join(cmd)) - proc = subprocess.run(cmd) - sys.exit(proc.returncode) + bod = CuBIDS(data_root=str(bids_dir), use_datalad=False) + fields = bod.get_all_metadata_fields() + logger.info("\n".join(fields)) + sys.exit(0) diff --git a/pyproject.toml b/pyproject.toml index d1c6cbe2..53b5852f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -35,7 +35,6 @@ dynamic = ["version"] Homepage = "https://github.com/PennLINC/cubids" Documentation = "https://www.cubids.readthedocs.io" Paper = "https://doi.org/10.1016/j.neuroimage.2022.119609" -"Docker Images" = "https://hub.docker.com/r/pennlinc/cubids/tags/" [project.optional-dependencies] doc = [