Skip to content

Commit

Permalink
Merge pull request #210 from SamGuay/improve_helper
Browse files Browse the repository at this point in the history
[FIX,ENH] - Improve dcm2bids_helper mod
  • Loading branch information
arnaudbore authored Jun 23, 2023
2 parents fc78036 + a6e8e33 commit ea31fe0
Show file tree
Hide file tree
Showing 6 changed files with 86 additions and 54 deletions.
2 changes: 1 addition & 1 deletion dcm2bids/cli/dcm2bids.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ def _build_arg_parser():
" will check if your output folder is BIDS valid. [%(default)s]\n"
f"bids-validator needs to be installed check: {DEFAULT.link_bids_validator}")

p.add_argument("--forceDcm2niix",
p.add_argument("--force_dcm2niix",
action="store_true",
help="Overwrite previous temporary dcm2niix "
"output if it exists.")
Expand Down
71 changes: 54 additions & 17 deletions dcm2bids/cli/dcm2bids_helper.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
# -*- coding: utf-8 -*-

"""helper module"""

"""
Converts DICOM files to NIfTI files including their JSON sidecars in a
temporary directory which can be inspected to make a dc2mbids config file.
"""
import logging
import argparse
from os.path import join as opj

import sys
import os
from pathlib import Path
from datetime import datetime
from dcm2bids.dcm2niix_gen import Dcm2niixGen
from dcm2bids.utils.args import assert_dirs_empty
from dcm2bids.utils.utils import DEFAULT
from dcm2bids.utils.logger import setup_logging


def _build_arg_parser():
Expand All @@ -19,11 +25,20 @@ def _build_arg_parser():
help="DICOM files directory.")

p.add_argument("-o", "--output_dir",
required=False, default=DEFAULT.cliOutputDir,
help="Output BIDS directory."
" (Default: %(default)s)")

p.add_argument('--force',
required=False,
default=Path(DEFAULT.cliOutputDir) / DEFAULT.tmpDirName /
DEFAULT.helperDir,
help="Output directory. (Default: [%(default)s]")

p.add_argument("-n", "--nest",
nargs="?", const=True, default=False, required=False,
help="Nest a directory in <output_dir>. Useful if many helper "
"runs are needed\nto make a config file due to slight "
"variations in MRI acquisitions.\n"
"Defaults to DICOM_DIR if no name is provided.\n"
"(Default: [%(default)s])")

p.add_argument('--force', '--force_dcm2niix',
dest='overwrite', action='store_true',
help='Force command to overwrite existing output files.')

Expand All @@ -34,14 +49,36 @@ def main():
"""Let's go"""
parser = _build_arg_parser()
args = parser.parse_args()

out_folder = opj(args.output_dir, 'tmp_dcm2bids', 'helper')
assert_dirs_empty(parser, args, out_folder)

app = Dcm2niixGen(dicomDirs=args.dicom_dir, bidsDir=args.output_dir)
rsl = app.run()
print("Example in:")
print(opj(args.output_dir, DEFAULT.tmpDirName, DEFAULT.helperDir))
out_dir = Path(args.output_dir)
log_path = (Path(DEFAULT.cliOutputDir)
/ DEFAULT.tmpDirName
/ "log"
/ f"helper_{datetime.now().isoformat().replace(':', '')}.log")
if args.nest:
if isinstance(args.nest, str):
log_path = Path(
str(log_path).replace("helper_",
f"helper_{args.nest.replace(os.path.sep, '-')}_"))
out_dir = out_dir / args.nest
else:
log_path = Path(str(log_path).replace(
"helper_", f"helper_{args.dicom_dir[0].replace(os.path.sep, '-')}_")
)
out_dir = out_dir / args.dicom_dir[0]

log_path.parent.mkdir(parents=True, exist_ok=True)
setup_logging("info", log_path)
logger = logging.getLogger(__name__)

logger.info("Running the following command: \n" + " ".join(sys.argv) + "\n")

assert_dirs_empty(parser, args, out_dir)

app = Dcm2niixGen(dicomDirs=args.dicom_dir, bidsDir=out_dir, helper=True)

rsl = app.run(force=args.overwrite)
logger.info(f"Helper files in: {out_dir}\n")
logger.info(f"Log file saved at {log_path}")

return rsl

Expand Down
8 changes: 4 additions & 4 deletions dcm2bids/dcm2bids_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ class Dcm2BidsGen(object):
output_dir (path): Path to the BIDS base folder
session (str): Optional label of a session
clobber (boolean): Overwrite file if already in BIDS folder
forceDcm2niix (boolean): Forces a cleaning of a previous execution of
force_dcm2niix (boolean): Forces a cleaning of a previous execution of
dcm2niix
log_level (str): logging level
"""
Expand All @@ -47,7 +47,7 @@ def __init__(
auto_extract_entities=DEFAULT.auto_extract_entities,
session=DEFAULT.session,
clobber=DEFAULT.clobber,
forceDcm2niix=DEFAULT.forceDcm2niix,
force_dcm2niix=DEFAULT.force_dcm2niix,
log_level=DEFAULT.logLevel,
**_
):
Expand All @@ -60,7 +60,7 @@ def __init__(
self.clobber = clobber
self.bids_validate = bids_validate
self.auto_extract_entities = auto_extract_entities
self.forceDcm2niix = forceDcm2niix
self.force_dcm2niix = force_dcm2niix
self.logLevel = log_level

# logging setup
Expand Down Expand Up @@ -113,7 +113,7 @@ def run(self):
check_latest()
check_latest("dcm2niix")

dcm2niix.run(self.forceDcm2niix)
dcm2niix.run(self.force_dcm2niix)

sidecars = []
for filename in dcm2niix.sidecarFiles:
Expand Down
28 changes: 15 additions & 13 deletions dcm2bids/dcm2niix_gen.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,20 @@ class Dcm2niixGen(object):
"""

def __init__(
self, dicomDirs, bidsDir, participant=None, options=DEFAULT.dcm2niixOptions
self,
dicomDirs,
bidsDir,
participant=None,
options=DEFAULT.dcm2niixOptions,
helper=False
):
self.logger = logging.getLogger(__name__)

self.sidecarsFiles = []

self.dicomDirs = dicomDirs
self.bidsDir = bidsDir
self.participant = participant
self.options = options
self.helper = helper

@property
def outputDir(self):
Expand All @@ -43,10 +47,12 @@ def outputDir(self):
A directory to save all the output files of dcm2niix
"""
tmpDir = self.participant.prefix if self.participant else DEFAULT.helperDir
tmpDir = self.bidsDir / DEFAULT.tmpDirName / tmpDir
if self.helper:
tmpDir = self.bidsDir
return tmpDir

return self.bidsDir / DEFAULT.tmpDirName / tmpDir

def run(self, force=False):
def run(self, force=False, helper=False):
""" Run dcm2niix if necessary
Args:
Expand All @@ -58,7 +64,7 @@ def run(self, force=False):
"""
try:
oldOutput = os.listdir(self.outputDir) != []
except:
except Exception:
oldOutput = False

if oldOutput and force:
Expand All @@ -69,8 +75,6 @@ def run(self, force=False):

shutil.rmtree(self.outputDir, ignore_errors=True)

# os.makedirs(self.outputDir, exist_ok=True)
# python2 compatibility
if not os.path.exists(self.outputDir):
os.makedirs(self.outputDir)

Expand All @@ -79,11 +83,9 @@ def run(self, force=False):
elif oldOutput:
self.logger.warning("Previous dcm2niix directory output found:")
self.logger.warning(self.outputDir)
self.logger.warning("Use --forceDcm2niix to rerun dcm2niix")
self.logger.warning("Use --force_dcm2niix to rerun dcm2niix \n")

else:
# os.makedirs(self.outputDir, exist_ok=True)
# python2 compatibility
if not os.path.exists(self.outputDir):
os.makedirs(self.outputDir)

Expand All @@ -101,7 +103,7 @@ def execute(self):

try:
output = output.decode()
except:
except Exception:
pass

self.logger.debug("\n%s", output)
Expand Down
29 changes: 11 additions & 18 deletions dcm2bids/utils/args.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# -*- coding: utf-8 -*-

import os
import shutil
from pathlib import Path
import os


def assert_dirs_empty(parser, args, required):
Expand All @@ -18,30 +19,22 @@ def assert_dirs_empty(parser, args, required):
required: string or list of paths to files
Required paths to be checked.
"""
def check(path):
if os.path.isdir(path):
if os.listdir(path):
def check(path: Path):
if path.is_dir():
if any(path.iterdir()):
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 "
f"Output directory {path}{os.sep} 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)
shutil.rmtree(path)

if isinstance(required, str):
required = [required]
required = Path(required)

for cur_dir in required:
for cur_dir in [required]:
check(cur_dir)


Expand Down
2 changes: 1 addition & 1 deletion dcm2bids/utils/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class DEFAULT(object):
bids_validate = False
auto_extract_entities = False
clobber = False
forceDcm2niix = False
force_dcm2niix = False
defaceTpl = None
logLevel = "WARNING"

Expand Down

0 comments on commit ea31fe0

Please sign in to comment.