From cfdae8858ea1744c8c35e9d856b86992065c0b08 Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Sat, 16 Apr 2022 23:26:07 -0400 Subject: [PATCH 01/11] suggestion_to_fix_path --- dcm2bids/dcm2bids.py | 43 ++++++++++++------------------------------- dcm2bids/dcm2niix.py | 5 +++-- dcm2bids/utils.py | 24 +++++++++++++++++++++--- docs/4-advanced.md | 2 +- 4 files changed, 37 insertions(+), 37 deletions(-) diff --git a/dcm2bids/dcm2bids.py b/dcm2bids/dcm2bids.py index 6b842e07..cc6653cb 100644 --- a/dcm2bids/dcm2bids.py +++ b/dcm2bids/dcm2bids.py @@ -13,7 +13,8 @@ from .logger import setup_logging from .sidecar import Sidecar, SidecarPairing from .structure import Participant -from .utils import DEFAULT, load_json, save_json, run_shell_command, splitext_ +from .utils import (DEFAULT, load_json, save_json, + splitext_, run_shell_command, valid_path) from .version import __version__, check_latest, dcm2niix_version @@ -47,8 +48,8 @@ def __init__( self._dicomDirs = [] self.dicomDirs = dicom_dir - self.bidsDir = output_dir - self.config = load_json(config) + self.bidsDir = valid_path(output_dir) + self.config = load_json(valid_path(config)) self.participant = Participant(participant, session) self.clobber = clobber self.forceDcm2niix = forceDcm2niix @@ -74,22 +75,25 @@ def dicomDirs(self): @dicomDirs.setter def dicomDirs(self, value): + if isinstance(value, list): dicom_dirs = value else: dicom_dirs = [value] dir_not_found = [] + valid_dirs = [] for _dir in dicom_dirs: + _dir = valid_path(_dir) if os.path.isdir(_dir): - pass + valid_dirs.append(_dir) else: dir_not_found.append(_dir) if dir_not_found: raise FileNotFoundError(dir_not_found) - self._dicomDirs = dicom_dirs + self._dicomDirs = valid_dirs def set_logger(self): """ Set a basic logger""" @@ -176,9 +180,11 @@ def move(self, acquisition, intendedForList): except FileNotFoundError: pass defaceTpl = self.config.get("defaceTpl") - cmd = defaceTpl.format(srcFile=srcFile, dstFile=dstFile) + cmd = [w.replace('srcFile', srcFile) for w in defaceTpl] + cmd = [w.replace('dstFile', dstFile) for w in defaceTpl] run_shell_command(cmd) + intendedForList[acquisition.indexSidecar].append(acquisition.dstIntendedFor + ext) elif ext == ".json": @@ -262,16 +268,6 @@ def get_arguments(): help="Set logging level", ) - parser.add_argument( - "-a", - "--anonymizer", - required=False, - action="store_true", - help=""" - This option no longer exists from the script in this release. - See:https://github.com/unfmontreal/Dcm2Bids/blob/master/README.md#defaceTpl""", - ) - args = parser.parse_args() return args @@ -280,21 +276,6 @@ def main(): """Let's go""" args = get_arguments() - if args.anonymizer: - print( - """ - The anonymizer option no longer exists from the script in this release - It is still possible to deface the anatomical nifti images - Please add "defaceTpl" key in the congifuration file - - For example, if you use the last version of pydeface, add: - "defaceTpl": "pydeface --outfile {dstFile} {srcFile}" - It is a template string and dcm2bids will replace {srcFile} and {dstFile} - by the source file (input) and the destination file (output) - """ - ) - return 1 - check_latest() check_latest("dcm2niix") diff --git a/dcm2bids/dcm2niix.py b/dcm2bids/dcm2niix.py index 5efcbe89..b59265b9 100644 --- a/dcm2bids/dcm2niix.py +++ b/dcm2bids/dcm2niix.py @@ -4,6 +4,7 @@ import logging import os +import shlex import shutil from glob import glob from .utils import DEFAULT, run_shell_command @@ -95,8 +96,8 @@ def execute(self): """ Execute dcm2niix for each directory in dicomDirs """ for dicomDir in self.dicomDirs: - commandTpl = "dcm2niix {} -o {} {}" - cmd = commandTpl.format(self.options, self.outputDir, dicomDir) + cmd = ['dcm2niix', *shlex.split(self.options), + '-o', self.outputDir, dicomDir] output = run_shell_command(cmd) try: diff --git a/dcm2bids/utils.py b/dcm2bids/utils.py index fbffa859..1c54931e 100644 --- a/dcm2bids/utils.py +++ b/dcm2bids/utils.py @@ -5,7 +5,8 @@ import json import logging import os -import shlex +from pathlib import PurePath +import re from collections import OrderedDict from subprocess import check_output @@ -110,10 +111,27 @@ def splitext_(path, extensions=None): def run_shell_command(commandLine): """ Wrapper of subprocess.check_output - Returns: Run command with arguments and return its output """ logger = logging.getLogger(__name__) logger.info("Running %s", commandLine) - return check_output(shlex.split(commandLine)) + return check_output(commandLine) + + +def valid_path(in_path): + """Assert that file exists. + + Parameters + ---------- + required_file: string path + Path to be checked. + """ + valid_path = re.sub(r'\\', os.path.sep, in_path) + valid_path = re.sub(r'\/', os.path.sep, valid_path) + valid_path = str(PurePath(valid_path)) + + if os.path.isfile(valid_path) or os.path.isdir(valid_path): + if os.path.exists(valid_path): + return valid_path + raise FileNotFoundError(in_path) diff --git a/docs/4-advanced.md b/docs/4-advanced.md index 3047b15e..3e87f24d 100644 --- a/docs/4-advanced.md +++ b/docs/4-advanced.md @@ -6,7 +6,7 @@ These optional configurations could be insert in the configuration file at the s { "searchMethod": "fnmatch", "caseSensitive": true, - "defaceTpl": "pydeface --outfile {dstFile} {srcFile}", + "defaceTpl": ["pydeface", "--outfile", "dstFile", "srcFile"], "description": [ ... ] From 3afcb61e633d2323f47287bd28385301e76d29f5 Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Sat, 16 Apr 2022 23:38:58 -0400 Subject: [PATCH 02/11] fix helper --- dcm2bids/helper.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/dcm2bids/helper.py b/dcm2bids/helper.py index 79521206..6e02cbd0 100644 --- a/dcm2bids/helper.py +++ b/dcm2bids/helper.py @@ -6,7 +6,7 @@ import os import sys from .dcm2niix import Dcm2niix -from .utils import DEFAULT +from .utils import DEFAULT, valid_path def get_arguments(): @@ -38,7 +38,12 @@ def get_arguments(): def main(): """Let's go""" args = get_arguments() - app = Dcm2niix(dicomDirs=args.dicom_dir, bidsDir=args.output_dir) + valid_dicom_dir = [] + for _dir in args.dicom_dir: + valid_dicom_dir.append(valid_path(_dir)) + + app = Dcm2niix(dicomDirs=valid_dicom_dir, + bidsDir=valid_path(args.output_dir)) rsl = app.run() print("Example in:") print(os.path.join(args.output_dir, DEFAULT.tmpDirName, DEFAULT.helperDir)) From def7876a01e8e6615d98f9c0541bb9f529d3cef1 Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Sat, 16 Apr 2022 23:48:47 -0400 Subject: [PATCH 03/11] remove re --- dcm2bids/utils.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/dcm2bids/utils.py b/dcm2bids/utils.py index 1c54931e..aebacecd 100644 --- a/dcm2bids/utils.py +++ b/dcm2bids/utils.py @@ -127,11 +127,10 @@ def valid_path(in_path): required_file: string path Path to be checked. """ - valid_path = re.sub(r'\\', os.path.sep, in_path) - valid_path = re.sub(r'\/', os.path.sep, valid_path) - valid_path = str(PurePath(valid_path)) + valid_path = str(PurePath(in_path)) if os.path.isfile(valid_path) or os.path.isdir(valid_path): if os.path.exists(valid_path): return valid_path + raise FileNotFoundError(in_path) From 46640c318a5ff4abda6f127adfb0795402cd724e Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Tue, 19 Apr 2022 08:23:49 -0400 Subject: [PATCH 04/11] fix typos --- dcm2bids/sidecar.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dcm2bids/sidecar.py b/dcm2bids/sidecar.py index f3ad1ae5..a973765b 100644 --- a/dcm2bids/sidecar.py +++ b/dcm2bids/sidecar.py @@ -86,7 +86,7 @@ class SidecarPairing(object): """ Args: sidecars (list): List of Sidecar objects - descriptions (list): List of dictionnaries describing acquisitions + descriptions (list): List of dictionaries describing acquisitions """ def __init__(self, sidecars, descriptions, searchMethod=DEFAULT.searchMethod, @@ -146,7 +146,7 @@ def caseSensitive(self, value): def build_graph(self): """ Test all the possible links between the list of sidecars and the - description dictionnaries and build a graph from it + description dictionaries and build a graph from it The graph is in a OrderedDict object. The keys are the Sidecars and the values are a list of possible descriptions From b21d6f3f1a7569e7f7a41a8ace03f9bb5762ee54 Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Wed, 20 Apr 2022 11:50:21 -0400 Subject: [PATCH 05/11] add type Path to input paths --- dcm2bids/dcm2bids.py | 130 +++++++++++++++++++------------------------ dcm2bids/helper.py | 12 ++-- dcm2bids/utils.py | 12 ++-- 3 files changed, 68 insertions(+), 86 deletions(-) diff --git a/dcm2bids/dcm2bids.py b/dcm2bids/dcm2bids.py index cc6653cb..c7aaa404 100644 --- a/dcm2bids/dcm2bids.py +++ b/dcm2bids/dcm2bids.py @@ -1,21 +1,25 @@ # -*- coding: utf-8 -*- -"""dcm2bids module""" +""" +Reorganising NIfTI files from dcm2niix into the Brain Imaging Data Structure +""" import argparse import logging import os +from pathlib import Path import platform import sys from datetime import datetime from glob import glob -from .dcm2niix import Dcm2niix -from .logger import setup_logging -from .sidecar import Sidecar, SidecarPairing -from .structure import Participant -from .utils import (DEFAULT, load_json, save_json, - splitext_, run_shell_command, valid_path) -from .version import __version__, check_latest, dcm2niix_version + +from dcm2bids.dcm2niix import Dcm2niix +from dcm2bids.logger import setup_logging +from dcm2bids.sidecar import Sidecar, SidecarPairing +from dcm2bids.structure import Participant +from dcm2bids.utils import (DEFAULT, load_json, save_json, + splitext_, run_shell_command, valid_path) +from dcm2bids.version import __version__, check_latest, dcm2niix_version class Dcm2bids(object): @@ -204,77 +208,55 @@ def move(self, acquisition, intendedForList): return intendedForList -def get_arguments(): - """Load arguments for main""" - parser = argparse.ArgumentParser( - formatter_class=argparse.RawDescriptionHelpFormatter, - description=""" -Reorganising NIfTI files from dcm2niix into the Brain Imaging Data Structure -dcm2bids {}""".format( - __version__ - ), - epilog=""" - Documentation at https://github.com/unfmontreal/Dcm2Bids - """, - ) - - parser.add_argument( - "-d", "--dicom_dir", required=True, nargs="+", help="DICOM directory(ies)" - ) - - parser.add_argument("-p", "--participant", required=True, help="Participant ID") - - parser.add_argument( - "-s", "--session", required=False, default=DEFAULT.cliSession, help="Session ID" - ) - - parser.add_argument( - "-c", - "--config", - required=True, - help="JSON configuration file (see example/config.json)", - ) - - parser.add_argument( - "-o", - "--output_dir", - required=False, - default=DEFAULT.cliOutputDir, - help="Output BIDS directory, Default: current directory ({})".format( - DEFAULT.cliOutputDir - ), - ) - - parser.add_argument( - "--forceDcm2niix", - required=False, - action="store_true", - help="Overwrite previous temporary dcm2niix output if it exists", - ) - - parser.add_argument( - "--clobber", - required=False, - action="store_true", - help="Overwrite output if it exists", - ) - - parser.add_argument( - "-l", - "--log_level", - required=False, - default=DEFAULT.cliLogLevel, - choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"], - help="Set logging level", - ) +def _build_arg_parser(): + p = argparse.ArgumentParser(description=__doc__, epilog=DEFAULT.EPILOG, + formatter_class=argparse.RawTextHelpFormatter) - args = parser.parse_args() - return args + p.add_argument("-d", "--dicom_dir", + type=Path, required=True, nargs="+", + help="DICOM directory(ies).") + + p.add_argument("-p", "--participant", + required=True, + help="Participant ID.") + + p.add_argument("-s", "--session", + required=False, + default=DEFAULT.cliSession, + help="Session ID.") + + p.add_argument("-c", "--config", + required=True, + help="JSON configuration file (see example/config.json).") + + p.add_argument("-o", "--output_dir", + required=False, + type=Path, + default=DEFAULT.cliOutputDir, + help="Output BIDS directory, [%(default)s]") + + p.add_argument("--forceDcm2niix", + action="store_true", + help="Overwrite previous temporary dcm2niix " + "output if it exists.") + + p.add_argument("--clobber", + action="store_true", + help="Overwrite output if it exists.") + + p.add_argument("-l", "--log_level", + required=False, + default=DEFAULT.cliLogLevel, + choices=["DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL"], + help="Set logging level. [%(default)s]") + + return p def main(): """Let's go""" - args = get_arguments() + parser = _build_arg_parser() + args = parser.parse_args() check_latest() check_latest("dcm2niix") diff --git a/dcm2bids/helper.py b/dcm2bids/helper.py index 06c4bdce..df806e40 100644 --- a/dcm2bids/helper.py +++ b/dcm2bids/helper.py @@ -4,25 +4,25 @@ import argparse import os +from pathlib import Path import sys -from .dcm2niix import Dcm2niix -from .utils import DEFAULT, assert_dirs_empty -EPILOG = """ - Documentation at https://github.com/unfmontreal/Dcm2Bids - """ +from dcm2bids.dcm2niix import Dcm2niix +from dcm2bids.utils import DEFAULT, assert_dirs_empty def _build_arg_parser(): - p = argparse.ArgumentParser(description=__doc__, epilog=EPILOG, + p = argparse.ArgumentParser(description=__doc__, epilog=DEFAULT.EPILOG, formatter_class=argparse.RawTextHelpFormatter) p.add_argument("-d", "--dicom_dir", + type=Path, required=True, nargs="+", help="DICOM files directory.") p.add_argument("-o", "--output_dir", required=False, default=DEFAULT.cliOutputDir, + type=Path, help="Output BIDS directory." " (Default: %(default)s)") diff --git a/dcm2bids/utils.py b/dcm2bids/utils.py index 95bd998e..f980e4c6 100644 --- a/dcm2bids/utils.py +++ b/dcm2bids/utils.py @@ -5,7 +5,7 @@ import json import logging import os -from pathlib import PurePath +from pathlib import Path import re from collections import OrderedDict import shlex @@ -20,6 +20,7 @@ class DEFAULT(object): cliSession = "" cliOutputDir = os.getcwd() cliLogLevel = "INFO" + EPILOG="Documentation at https://github.com/unfmontreal/Dcm2Bids" # dcm2bids.py outputDir = cliOutputDir @@ -126,14 +127,13 @@ def valid_path(in_path): Parameters ---------- - required_file: string path + required_file: Path Path to be checked. """ - valid_path = str(PurePath(in_path)) - if os.path.isfile(valid_path) or os.path.isdir(valid_path): - if os.path.exists(valid_path): - return valid_path + if in_path.isfile() or in_path.isdir(): + if in_path.exists(): + return in_path.name raise FileNotFoundError(in_path) From cfa4295624e4a4dec77fb6b6b4147df973bb47d8 Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Wed, 20 Apr 2022 12:17:13 -0400 Subject: [PATCH 06/11] fix check dir and files --- dcm2bids/dcm2bids.py | 7 ++++--- dcm2bids/utils.py | 13 +++++++------ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/dcm2bids/dcm2bids.py b/dcm2bids/dcm2bids.py index c7aaa404..1d0c4973 100644 --- a/dcm2bids/dcm2bids.py +++ b/dcm2bids/dcm2bids.py @@ -52,8 +52,8 @@ def __init__( self._dicomDirs = [] self.dicomDirs = dicom_dir - self.bidsDir = valid_path(output_dir) - self.config = load_json(valid_path(config)) + self.bidsDir = valid_path(output_dir, "folder") + self.config = load_json(valid_path(config, "folder")) self.participant = Participant(participant, session) self.clobber = clobber self.forceDcm2niix = forceDcm2niix @@ -88,7 +88,7 @@ def dicomDirs(self, value): dir_not_found = [] valid_dirs = [] for _dir in dicom_dirs: - _dir = valid_path(_dir) + _dir = valid_path(_dir, "folder") if os.path.isdir(_dir): valid_dirs.append(_dir) else: @@ -226,6 +226,7 @@ def _build_arg_parser(): help="Session ID.") p.add_argument("-c", "--config", + type=Path, required=True, help="JSON configuration file (see example/config.json).") diff --git a/dcm2bids/utils.py b/dcm2bids/utils.py index f980e4c6..5c23838a 100644 --- a/dcm2bids/utils.py +++ b/dcm2bids/utils.py @@ -122,7 +122,7 @@ def run_shell_command(commandLine): return check_output(commandLine) -def valid_path(in_path): +def valid_path(in_path, type="folder"): """Assert that file exists. Parameters @@ -131,11 +131,12 @@ def valid_path(in_path): Path to be checked. """ - if in_path.isfile() or in_path.isdir(): - if in_path.exists(): - return in_path.name - - raise FileNotFoundError(in_path) + if in_path.is_file() or in_path.is_dir(): + return in_path.name + elif type=='folder': + raise NotADirectoryError(in_path) + else: + raise FileNotFoundError(in_path) def assert_dirs_empty(parser, args, required): From f2f241d112bd22962d42809a3da63a3a5d8d0214 Mon Sep 17 00:00:00 2001 From: arnaudbore Date: Wed, 20 Apr 2022 12:58:35 -0400 Subject: [PATCH 07/11] fix tests --- dcm2bids/dcm2bids.py | 14 +++----------- dcm2bids/utils.py | 23 +++++++++++++++-------- 2 files changed, 18 insertions(+), 19 deletions(-) diff --git a/dcm2bids/dcm2bids.py b/dcm2bids/dcm2bids.py index 1d0c4973..1b1bab51 100644 --- a/dcm2bids/dcm2bids.py +++ b/dcm2bids/dcm2bids.py @@ -52,8 +52,8 @@ def __init__( self._dicomDirs = [] self.dicomDirs = dicom_dir - self.bidsDir = valid_path(output_dir, "folder") - self.config = load_json(valid_path(config, "folder")) + self.bidsDir = valid_path(output_dir, type="folder") + self.config = load_json(valid_path(config, type="file")) self.participant = Participant(participant, session) self.clobber = clobber self.forceDcm2niix = forceDcm2niix @@ -85,17 +85,9 @@ def dicomDirs(self, value): else: dicom_dirs = [value] - dir_not_found = [] valid_dirs = [] for _dir in dicom_dirs: - _dir = valid_path(_dir, "folder") - if os.path.isdir(_dir): - valid_dirs.append(_dir) - else: - dir_not_found.append(_dir) - - if dir_not_found: - raise FileNotFoundError(dir_not_found) + valid_dirs.append(valid_path(_dir, "folder")) self._dicomDirs = valid_dirs diff --git a/dcm2bids/utils.py b/dcm2bids/utils.py index 5c23838a..75b54188 100644 --- a/dcm2bids/utils.py +++ b/dcm2bids/utils.py @@ -130,14 +130,21 @@ def valid_path(in_path, type="folder"): required_file: Path Path to be checked. """ - - if in_path.is_file() or in_path.is_dir(): - return in_path.name - elif type=='folder': - raise NotADirectoryError(in_path) - else: - raise FileNotFoundError(in_path) - + if isinstance(in_path, str): + in_path = Path(in_path) + + if type=='folder': + if in_path.is_dir() or in_path.parent.is_dir(): + return str(in_path) + else: + raise NotADirectoryError(in_path) + elif type=="file": + if in_path.is_file(): + return str(in_path) + else: + raise FileNotFoundError(in_path) + + raise TypeError(type) def assert_dirs_empty(parser, args, required): """ From a3b3e9b17d179ee16ef4c0319f014ceead5e12ea Mon Sep 17 00:00:00 2001 From: Samuel Guay Date: Fri, 22 Apr 2022 08:26:33 -0400 Subject: [PATCH 08/11] fix typos --- dcm2bids/structure.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dcm2bids/structure.py b/dcm2bids/structure.py index 72156820..406bfb5a 100644 --- a/dcm2bids/structure.py +++ b/dcm2bids/structure.py @@ -255,8 +255,8 @@ def setDstFile(self): if len(suffix_list) != 1: self.logger.warning("There was more than one suffix found " - f"({suffix_list}). this is not BIDS " - "compliant. Make sure you know what" + f"({suffix_list}). This is not BIDS " + "compliant. Make sure you know what " "you are doing.") if current_name != new_name: From 30557c8eaa0b2fb9d50af5eb2859848c7fba4d20 Mon Sep 17 00:00:00 2001 From: Samuel Guay Date: Fri, 22 Apr 2022 10:27:18 -0400 Subject: [PATCH 09/11] Check whether helper/ is _really_ empty --- dcm2bids/helper.py | 11 +++++------ dcm2bids/utils.py | 43 ++++++++++++++++++++++++------------------- 2 files changed, 29 insertions(+), 25 deletions(-) diff --git a/dcm2bids/helper.py b/dcm2bids/helper.py index df806e40..bcb77ffd 100644 --- a/dcm2bids/helper.py +++ b/dcm2bids/helper.py @@ -21,10 +21,10 @@ def _build_arg_parser(): help="DICOM files directory.") p.add_argument("-o", "--output_dir", - required=False, default=DEFAULT.cliOutputDir, + required=False, default=Path.cwd(), type=Path, - help="Output BIDS directory." - " (Default: %(default)s)") + help="Output BIDS directory. " + "(Default: %(default)s)") p.add_argument('--force', dest='overwrite', action='store_true', @@ -37,12 +37,11 @@ def main(): """Let's go""" parser = _build_arg_parser() args = parser.parse_args() - out_folder = os.path.join(args.output_dir, 'tmp_dcm2bids', 'helper') + out_folder = args.output_dir / DEFAULT.tmpDirName / DEFAULT.helperDir assert_dirs_empty(parser, args, out_folder) app = Dcm2niix(dicomDirs=args.dicom_dir, bidsDir=args.output_dir) rsl = app.run() - print("Example in:") - print(os.path.join(args.output_dir, DEFAULT.tmpDirName, DEFAULT.helperDir)) + print(f"Example in: {out_folder}") return rsl diff --git a/dcm2bids/utils.py b/dcm2bids/utils.py index 75b54188..4ee02fa1 100644 --- a/dcm2bids/utils.py +++ b/dcm2bids/utils.py @@ -163,25 +163,30 @@ def assert_dirs_empty(parser, args, required): If true, create the directory if it does not exist. """ def check(path): - if os.path.isdir(path): - if not args.overwrite: - parser.error( - f"Output directory {path} isn't empty, so some files " - "could be overwritten or deleted.\nRerun the command with " - "--force option to overwrite existing output files.") - else: - for the_file in os.listdir(path): - file_path = os.path.join(path, the_file) - try: - if os.path.isfile(file_path): - os.unlink(file_path) - elif os.path.isdir(file_path): - shutil.rmtree(file_path) - except Exception as e: - print(e) - - if isinstance(required, str): - required = [required] + if not path.is_dir(): + return + + if not any(path.iterdir()): + return + + if not args.overwrite: + parser.error( + f"Output directory {path} isn't empty, so some files " + "could be overwritten or deleted.\nRerun the command with " + "--force option to overwrite existing output files.") + else: + for the_file in path.iterdir(): + file_path = path / the_file + try: + if file_path.is_file(): + file_path.unlink() + elif file_path.is_dir(): + shutil.rmtree(file_path) + except Exception as e: + print(e) + + if isinstance(required, str) or isinstance(required, Path): + required = [Path(required)] for cur_dir in required: check(cur_dir) From f7f458306a984039b2f9a030120cb40091fc1d4f Mon Sep 17 00:00:00 2001 From: Samuel Guay Date: Fri, 22 Apr 2022 10:49:05 -0400 Subject: [PATCH 10/11] Convert path-like str object to Path --- dcm2bids/dcm2bids.py | 33 +++++++++------------------------ dcm2bids/dcm2niix.py | 9 ++++----- dcm2bids/structure.py | 2 +- 3 files changed, 14 insertions(+), 30 deletions(-) diff --git a/dcm2bids/dcm2bids.py b/dcm2bids/dcm2bids.py index 1b1bab51..b2a174bc 100644 --- a/dcm2bids/dcm2bids.py +++ b/dcm2bids/dcm2bids.py @@ -80,31 +80,17 @@ def dicomDirs(self): @dicomDirs.setter def dicomDirs(self, value): - if isinstance(value, list): - dicom_dirs = value - else: - dicom_dirs = [value] + dicom_dirs = value if isinstance(value, list) else [value] - valid_dirs = [] - for _dir in dicom_dirs: - valid_dirs.append(valid_path(_dir, "folder")) + valid_dirs = [valid_path(_dir, "folder") for _dir in dicom_dirs] self._dicomDirs = valid_dirs def set_logger(self): """ Set a basic logger""" - logDir = os.path.join(self.bidsDir, DEFAULT.tmpDirName, "log") - logFile = os.path.join( - logDir, - "{}_{}.log".format( - self.participant.prefix, datetime.now().isoformat().replace(":", "") - ), - ) - - # os.makedirs(logdir, exist_ok=True) - # python2 compatibility - if not os.path.exists(logDir): - os.makedirs(logDir) + logDir = self.bidsDir / DEFAULT.tmpDirName / "log" + logFile = logDir / f"{self.participant.prefix}_{datetime.now().isoformat().replace(':', '')}.log" + logDir.mkdir(parents=True, exist_ok=True) setup_logging(self.logLevel, logFile) self.logger = logging.getLogger(__name__) @@ -151,18 +137,17 @@ def move(self, acquisition, intendedForList): _, ext = splitext_(srcFile) dstFile = os.path.join(self.bidsDir, acquisition.dstRoot + ext) - if not os.path.exists(os.path.dirname(dstFile)): - os.makedirs(os.path.dirname(dstFile)) + dstFile.parent.mkdir(parents = True, exist_ok = True) # checking if destination file exists - if os.path.isfile(dstFile): + if dstFile.exists(): self.logger.info("'%s' already exists", dstFile) if self.clobber: - self.logger.info("Overwriting because of 'clobber' option") + self.logger.info("Overwriting because of --clobber option") else: - self.logger.info("Use clobber option to overwrite") + self.logger.info("Use --clobber option to overwrite") continue # it's an anat nifti file and the user using a deface script diff --git a/dcm2bids/dcm2niix.py b/dcm2bids/dcm2niix.py index b59265b9..60ac51ae 100644 --- a/dcm2bids/dcm2niix.py +++ b/dcm2bids/dcm2niix.py @@ -4,6 +4,7 @@ import logging import os +from pathlib import Path import shlex import shutil from glob import glob @@ -41,11 +42,9 @@ def outputDir(self): Returns: A directory to save all the output files of dcm2niix """ - if self.participant: - tmpDir = self.participant.prefix - else: - tmpDir = DEFAULT.helperDir - return os.path.join(self.bidsDir, DEFAULT.tmpDirName, tmpDir) + tmpDir = self.participant.prefix if self.participant else DEFAULT.helperDir + + return self.bidsDir / DEFAULT.tmpDirName / tmpDir def run(self, force=False): """ Run dcm2niix if necessary diff --git a/dcm2bids/structure.py b/dcm2bids/structure.py index 406bfb5a..97b08aa4 100644 --- a/dcm2bids/structure.py +++ b/dcm2bids/structure.py @@ -251,7 +251,7 @@ def setDstFile(self): self.logger.warning("Entity \"{}\"".format(list(current_dict.keys())) + " is not a valid BIDS entity.") - new_name += f"_{'_'.join(suffix_list)}" # Allow multiple single key (without value) + new_name += f"_{'_'.join(suffix_list)}" # Allow multiple single keys (without value) if len(suffix_list) != 1: self.logger.warning("There was more than one suffix found " From 882e055612b07e359f553796bbe90b29495d9e37 Mon Sep 17 00:00:00 2001 From: Samuel Guay Date: Fri, 22 Apr 2022 14:10:13 -0400 Subject: [PATCH 11/11] Change argparse default + improve suffix handling --- dcm2bids/dcm2bids.py | 18 +++++++++--------- dcm2bids/utils.py | 16 +++++++--------- 2 files changed, 16 insertions(+), 18 deletions(-) diff --git a/dcm2bids/dcm2bids.py b/dcm2bids/dcm2bids.py index b2a174bc..ea305c2b 100644 --- a/dcm2bids/dcm2bids.py +++ b/dcm2bids/dcm2bids.py @@ -134,8 +134,8 @@ def move(self, acquisition, intendedForList): """Move an acquisition to BIDS format""" for srcFile in glob(acquisition.srcRoot + ".*"): - _, ext = splitext_(srcFile) - dstFile = os.path.join(self.bidsDir, acquisition.dstRoot + ext) + ext = Path(srcFile).suffixes + dstFile = (self.bidsDir / acquisition.dstRoot).with_suffix("".join(ext)) dstFile.parent.mkdir(parents = True, exist_ok = True) @@ -153,9 +153,9 @@ def move(self, acquisition, intendedForList): # it's an anat nifti file and the user using a deface script if ( self.config.get("defaceTpl") - and acquisition.dataType == "anat" + and acquisition.dataType == "func" and ".nii" in ext - ): + ): try: os.remove(dstFile) except FileNotFoundError: @@ -166,9 +166,9 @@ def move(self, acquisition, intendedForList): cmd = [w.replace('dstFile', dstFile) for w in defaceTpl] run_shell_command(cmd) - intendedForList[acquisition.indexSidecar].append(acquisition.dstIntendedFor + ext) + intendedForList[acquisition.indexSidecar].append(acquisition.dstIntendedFor + "".join(ext)) - elif ext == ".json": + elif ".json" in ext: data = acquisition.dstSidecarData(self.config["descriptions"], intendedForList) save_json(dstFile, data) @@ -199,7 +199,7 @@ def _build_arg_parser(): p.add_argument("-s", "--session", required=False, - default=DEFAULT.cliSession, + default="", help="Session ID.") p.add_argument("-c", "--config", @@ -210,8 +210,8 @@ def _build_arg_parser(): p.add_argument("-o", "--output_dir", required=False, type=Path, - default=DEFAULT.cliOutputDir, - help="Output BIDS directory, [%(default)s]") + default=Path.cwd(), + help="Output BIDS directory. (Default: %(default)s)") p.add_argument("--forceDcm2niix", action="store_true", diff --git a/dcm2bids/utils.py b/dcm2bids/utils.py index 4ee02fa1..d487157f 100644 --- a/dcm2bids/utils.py +++ b/dcm2bids/utils.py @@ -17,14 +17,12 @@ class DEFAULT(object): """ Default values of the package""" # cli dcm2bids - cliSession = "" - cliOutputDir = os.getcwd() cliLogLevel = "INFO" EPILOG="Documentation at https://github.com/unfmontreal/Dcm2Bids" # dcm2bids.py - outputDir = cliOutputDir - session = cliSession # also Participant object + outputDir = Path.cwd() + session = "" # also Participant object clobber = False forceDcm2niix = False defaceTpl = None @@ -67,7 +65,7 @@ def load_json(filename): def save_json(filename, data): - with open(filename, "w") as f: + with filename.open("w") as f: json.dump(data, f, indent=4) @@ -133,14 +131,14 @@ def valid_path(in_path, type="folder"): if isinstance(in_path, str): in_path = Path(in_path) - if type=='folder': + if type == 'folder': if in_path.is_dir() or in_path.parent.is_dir(): - return str(in_path) + return in_path else: raise NotADirectoryError(in_path) - elif type=="file": + elif type == "file": if in_path.is_file(): - return str(in_path) + return in_path else: raise FileNotFoundError(in_path)