Skip to content

Commit 8f6b584

Browse files
author
Steven Tilley
committed
Refactor internal functions to use bids_options
Internal functions now check whether bids_options is None instead of checking the boolean bids. Also place bids options related help in the help field of the argparse "bids" argument.
1 parent 584144f commit 8f6b584

File tree

3 files changed

+45
-65
lines changed

3 files changed

+45
-65
lines changed

heudiconv/cli/run.py

Lines changed: 13 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,6 @@
1818

1919
INIT_MSG = "Running {packname} version {version}".format
2020

21-
BIDS_OPTIONS = [('help', 'Display this help message'),
22-
('notop', 'Skip creating of top-level bids files. '
23-
'Useful when running in batch mode to prevent '
24-
'possible race conditions.')]
25-
2621

2722
def is_interactive():
2823
"""Return True if all in/outs are tty"""
@@ -103,20 +98,9 @@ def process_extra_commands(outdir, args):
10398
return
10499

105100

106-
def help_bids():
107-
sys.stderr.write('bids specific options can be passed after the bids flag.\n'
108-
'For example, "--bids notop".\n'
109-
'The currently supported options are:\n')
110-
for option, helpstr in BIDS_OPTIONS:
111-
sys.stderr.write('{}: {}\n'.format(option, helpstr))
112-
113-
114101
def main(argv=None):
115102
parser = get_parser()
116103
args = parser.parse_args(argv)
117-
if 'help' in args.bids:
118-
help_bids()
119-
sys.exit(1)
120104
# exit if nothing to be done
121105
if not args.files and not args.dicom_dir_template and not args.command:
122106
lgr.warning("Nothing to be done - displaying usage help")
@@ -129,18 +113,6 @@ def main(argv=None):
129113
import numpy
130114
numpy.random.seed(args.random_seed)
131115
# Ensure only supported bids options are passed
132-
allowed_options = [option for option, _ in BIDS_OPTIONS]
133-
if args.bids is not None:
134-
for bids_option in args.bids:
135-
if bids_option not in allowed_options:
136-
lgr.warning("{} is not a valid bids option - displaying bids options help".format(bids_option))
137-
help_bids()
138-
sys.exit(1)
139-
args.bids_options = args.bids
140-
args.bids = True
141-
else:
142-
args.bids_options = []
143-
args.bids = False
144116
if args.debug:
145117
lgr.setLevel(logging.DEBUG)
146118
# Should be possible but only with a single subject -- will be used to
@@ -212,9 +184,14 @@ def get_parser():
212184
'is none')
213185
parser.add_argument('-b', '--bids', nargs='*',
214186
metavar=('BIDSOPTION1', 'BIDSOPTION2'),
215-
help='flag for output into BIDS structure. '
216-
'Can also take bids specific options. Use --bids help '
217-
'for more information.')
187+
choices=['notop'],
188+
dest='bids_options',
189+
help='flag for output into BIDS structure. Can also '
190+
'take bids specific options, e.g., --bids notop.'
191+
'The only currently supported options is'
192+
'"notop", which skips creation of top-level bids '
193+
'files. This is useful when running in batch mode to '
194+
'prevent possible race conditions.')
218195
parser.add_argument('--overwrite', action='store_true', default=False,
219196
help='flag to allow overwriting existing converted files')
220197
parser.add_argument('--datalad', action='store_true',
@@ -334,7 +311,8 @@ def process_args(args):
334311
from ..external.dlad import prepare_datalad
335312
dlad_sid = sid if not anon_sid else anon_sid
336313
dl_msg = prepare_datalad(anon_study_outdir, anon_outdir, dlad_sid,
337-
session, seqinfo, dicoms, args.bids)
314+
session, seqinfo, dicoms,
315+
args.bids_options)
338316

339317
lgr.info("PROCESSING STARTS: {0}".format(
340318
str(dict(subject=sid, outdir=study_outdir, session=session))))
@@ -348,12 +326,11 @@ def process_args(args):
348326
anon_outdir=anon_study_outdir,
349327
with_prov=args.with_prov,
350328
ses=session,
351-
bids=args.bids,
329+
bids_options=args.bids_options,
352330
seqinfo=seqinfo,
353331
min_meta=args.minmeta,
354332
overwrite=args.overwrite,
355-
dcmconfig=args.dcmconfig,
356-
bids_options=args.bids_options,)
333+
dcmconfig=args.dcmconfig,)
357334

358335
lgr.info("PROCESSING DONE: {0}".format(
359336
str(dict(subject=sid, outdir=study_outdir, session=session))))
@@ -366,7 +343,7 @@ def process_args(args):
366343
# also in batch mode might fail since we have no locking ATM
367344
# and theoretically no need actually to save entire study
368345
# we just need that
369-
add_to_datalad(outdir, study_outdir, msg, args.bids)
346+
add_to_datalad(outdir, study_outdir, msg, args.bids_options)
370347

371348
# if args.bids:
372349
# # Let's populate BIDS templates for folks to take care about

heudiconv/convert.py

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -79,16 +79,16 @@ def conversion_info(subject, outdir, info, filegroup, ses):
7979

8080

8181
def prep_conversion(sid, dicoms, outdir, heuristic, converter, anon_sid,
82-
anon_outdir, with_prov, ses, bids, seqinfo, min_meta,
83-
overwrite, dcmconfig, bids_options):
82+
anon_outdir, with_prov, ses, bids_options, seqinfo, min_meta,
83+
overwrite, dcmconfig):
8484
if dicoms:
8585
lgr.info("Processing %d dicoms", len(dicoms))
8686
elif seqinfo:
8787
lgr.info("Processing %d pre-sorted seqinfo entries", len(seqinfo))
8888
else:
8989
raise ValueError("neither dicoms nor seqinfo dict was provided")
9090

91-
if bids:
91+
if bids_options is not None:
9292
if not sid:
9393
raise ValueError(
9494
"BIDS requires alphanumeric subject ID. Got an empty value")
@@ -102,7 +102,7 @@ def prep_conversion(sid, dicoms, outdir, heuristic, converter, anon_sid,
102102

103103
# Generate heudiconv info folder
104104
idir = op.join(outdir, '.heudiconv', anon_sid)
105-
if bids and ses:
105+
if bids_options is not None and ses:
106106
idir = op.join(idir, 'ses-%s' % str(ses))
107107
if anon_outdir == outdir:
108108
idir = op.join(idir, 'info')
@@ -177,7 +177,7 @@ def prep_conversion(sid, dicoms, outdir, heuristic, converter, anon_sid,
177177
write_config(edit_file, info)
178178
save_json(filegroup_file, filegroup)
179179

180-
if bids:
180+
if bids_options is not None:
181181
# the other portion of the path would mimic BIDS layout
182182
# so we don't need to worry here about sub, ses at all
183183
tdir = anon_outdir
@@ -192,7 +192,7 @@ def prep_conversion(sid, dicoms, outdir, heuristic, converter, anon_sid,
192192
scaninfo_suffix=getattr(heuristic, 'scaninfo_suffix', '.json'),
193193
custom_callable=getattr(heuristic, 'custom_callable', None),
194194
with_prov=with_prov,
195-
bids=bids,
195+
bids_options=bids_options,
196196
outdir=tdir,
197197
min_meta=min_meta,
198198
overwrite=overwrite,
@@ -201,7 +201,7 @@ def prep_conversion(sid, dicoms, outdir, heuristic, converter, anon_sid,
201201
for item_dicoms in filegroup.values():
202202
clear_temp_dicoms(item_dicoms)
203203

204-
if bids and 'notop' not in bids_options:
204+
if bids_options is not None and 'notop' not in bids_options:
205205
if seqinfo:
206206
keys = list(seqinfo)
207207
add_participant_record(anon_outdir,
@@ -213,7 +213,7 @@ def prep_conversion(sid, dicoms, outdir, heuristic, converter, anon_sid,
213213

214214

215215
def convert(items, converter, scaninfo_suffix, custom_callable, with_prov,
216-
bids, outdir, min_meta, overwrite, symlink=True, prov_file=None,
216+
bids_options, outdir, min_meta, overwrite, symlink=True, prov_file=None,
217217
dcmconfig=None):
218218
"""Perform actual conversion (calls to converter etc) given info from
219219
heuristic's `infotodict`
@@ -256,7 +256,7 @@ def convert(items, converter, scaninfo_suffix, custom_callable, with_prov,
256256
# We want to create this dir only if we are converting it to nifti,
257257
# or if we're using BIDS
258258
dicom_only = outtypes == ('dicom',)
259-
if not(dicom_only and bids) and not op.exists(prefix_dirname):
259+
if not(dicom_only and (bids_options is not None)) and not op.exists(prefix_dirname):
260260
os.makedirs(prefix_dirname)
261261

262262
for outtype in outtypes:
@@ -265,7 +265,7 @@ def convert(items, converter, scaninfo_suffix, custom_callable, with_prov,
265265
lgr.debug("Includes the following dicoms: %s", item_dicoms)
266266

267267
if outtype == 'dicom':
268-
convert_dicom(item_dicoms, bids, prefix,
268+
convert_dicom(item_dicoms, bids_options, prefix,
269269
outdir, tempdirs, symlink, overwrite)
270270
elif outtype in ['nii', 'nii.gz']:
271271
assert converter == 'dcm2niix', ('Invalid converter '
@@ -279,16 +279,16 @@ def convert(items, converter, scaninfo_suffix, custom_callable, with_prov,
279279

280280
# run conversion through nipype
281281
res, prov_file = nipype_convert(item_dicoms, prefix, with_prov,
282-
bids, tmpdir, dcmconfig)
282+
bids_options, tmpdir, dcmconfig)
283283

284-
bids_outfiles = save_converted_files(res, item_dicoms, bids,
284+
bids_outfiles = save_converted_files(res, item_dicoms, bids_options,
285285
outtype, prefix,
286286
outname_bids,
287287
overwrite=overwrite)
288288

289289
# save acquisition time information if it's BIDS
290290
# at this point we still have acquisition date
291-
if bids:
291+
if bids_options is not None:
292292
save_scans_key(item, bids_outfiles)
293293
# Fix up and unify BIDS files
294294
tuneup_bids_json_files(bids_outfiles)
@@ -310,7 +310,7 @@ def convert(items, converter, scaninfo_suffix, custom_callable, with_prov,
310310
elif not bids_outfiles:
311311
lgr.debug("No BIDS files were produced, nothing to embed to then")
312312
elif outname:
313-
embed_metadata_from_dicoms(bids, item_dicoms, outname, outname_bids,
313+
embed_metadata_from_dicoms(bids_options, item_dicoms, outname, outname_bids,
314314
prov_file, scaninfo, tempdirs, with_prov,
315315
min_meta)
316316
if scaninfo and op.exists(scaninfo):
@@ -326,16 +326,17 @@ def convert(items, converter, scaninfo_suffix, custom_callable, with_prov,
326326
custom_callable(*item)
327327

328328

329-
def convert_dicom(item_dicoms, bids, prefix,
329+
def convert_dicom(item_dicoms, bids_options, prefix,
330330
outdir, tempdirs, symlink, overwrite):
331331
"""Save DICOMs as output (default is by symbolic link)
332332
333333
Parameters
334334
----------
335335
item_dicoms : list of filenames
336336
DICOMs to save
337-
bids : bool
338-
Save to BIDS format
337+
bids_options : list or None
338+
If not None then save to BIDS format. List may be empty
339+
or contain bids specific options
339340
prefix : string
340341
Conversion outname
341342
outdir : string
@@ -352,7 +353,7 @@ def convert_dicom(item_dicoms, bids, prefix,
352353
-------
353354
None
354355
"""
355-
if bids:
356+
if bids_options is not None:
356357
# mimic the same hierarchy location as the prefix
357358
# although it could all have been done probably
358359
# within heuristic really
@@ -383,7 +384,7 @@ def convert_dicom(item_dicoms, bids, prefix,
383384
shutil.copyfile(filename, outfile)
384385

385386

386-
def nipype_convert(item_dicoms, prefix, with_prov, bids, tmpdir, dcmconfig=None):
387+
def nipype_convert(item_dicoms, prefix, with_prov, bids_options, tmpdir, dcmconfig=None):
387388
"""
388389
Converts DICOMs grouped from heuristic using Nipype's Dcm2niix interface.
389390
@@ -395,8 +396,9 @@ def nipype_convert(item_dicoms, prefix, with_prov, bids, tmpdir, dcmconfig=None)
395396
Heuristic output path
396397
with_prov : Bool
397398
Store provenance information
398-
bids : Bool
399-
Output BIDS sidecar JSONs
399+
bids_options : List or None
400+
If not None then output BIDS sidecar JSONs
401+
List may contain bids specific options
400402
tmpdir : Directory
401403
Conversion working directory
402404
dcmconfig : File (optional)
@@ -425,7 +427,7 @@ def nipype_convert(item_dicoms, prefix, with_prov, bids, tmpdir, dcmconfig=None)
425427
convertnode.inputs.terminal_output = 'allatonce'
426428
else:
427429
convertnode.terminal_output = 'allatonce'
428-
convertnode.inputs.bids_format = bids
430+
convertnode.inputs.bids_format = bids_options is not None
429431
eg = convertnode.run()
430432

431433
# prov information
@@ -439,7 +441,7 @@ def nipype_convert(item_dicoms, prefix, with_prov, bids, tmpdir, dcmconfig=None)
439441
return eg, prov_file
440442

441443

442-
def save_converted_files(res, item_dicoms, bids, outtype, prefix, outname_bids, overwrite):
444+
def save_converted_files(res, item_dicoms, bids_options, outtype, prefix, outname_bids, overwrite):
443445
"""Copy converted files from tempdir to output directory.
444446
Will rename files if necessary.
445447
@@ -449,8 +451,9 @@ def save_converted_files(res, item_dicoms, bids, outtype, prefix, outname_bids,
449451
Nipype conversion Node with results
450452
item_dicoms: list of filenames
451453
DICOMs converted
452-
bids : bool
453-
Option to save to BIDS
454+
bids : list or None
455+
If not list save to BIDS
456+
List may contain bids specific options
454457
prefix : string
455458
456459
Returns
@@ -481,7 +484,7 @@ def save_converted_files(res, item_dicoms, bids, outtype, prefix, outname_bids,
481484
# dwi etc which might spit out multiple files
482485

483486
suffixes = ([str(i+1) for i in range(len(res_files))]
484-
if bids else None)
487+
if (bids_options is not None) else None)
485488

486489
if not suffixes:
487490
lgr.warning("Following series files likely have "

heudiconv/dicoms.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -429,15 +429,15 @@ def embed_nifti(dcmfiles, niftifile, infofile, bids_info, min_meta):
429429
return niftifile, infofile
430430

431431

432-
def embed_metadata_from_dicoms(bids, item_dicoms, outname, outname_bids,
432+
def embed_metadata_from_dicoms(bids_options, item_dicoms, outname, outname_bids,
433433
prov_file, scaninfo, tempdirs, with_prov,
434434
min_meta):
435435
"""
436436
Enhance sidecar information file with more information from DICOMs
437437
438438
Parameters
439439
----------
440-
bids
440+
bids_options
441441
item_dicoms
442442
outname
443443
outname_bids
@@ -466,7 +466,7 @@ def embed_metadata_from_dicoms(bids, item_dicoms, outname, outname_bids,
466466
embedfunc.inputs.niftifile = op.abspath(outname)
467467
embedfunc.inputs.infofile = op.abspath(scaninfo)
468468
embedfunc.inputs.min_meta = min_meta
469-
embedfunc.inputs.bids_info = load_json(op.abspath(outname_bids)) if bids else None
469+
embedfunc.inputs.bids_info = load_json(op.abspath(outname_bids)) if (bids_options is not None) else None
470470
embedfunc.base_dir = tmpdir
471471
cwd = os.getcwd()
472472

0 commit comments

Comments
 (0)