Skip to content

Commit 8ee3168

Browse files
committed
enh(interface): Add an allowed_entities setting in DerivativesDataSink
Permit setting a list of ``allowed_entities`` at the instantiation time of ``DerivativesDataSink``s so that it is possible to create arbitrary, dynamic BIDS entities for the output file name without confusion with dynamic metadata keys. The reason to add this feature is to allow a more flexible interface for derivatives generated via iterables in the context of nipreps/fmriprep#1558.
1 parent 2a2586f commit 8ee3168

File tree

1 file changed

+32
-4
lines changed

1 file changed

+32
-4
lines changed

niworkflows/interfaces/bids.py

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,17 @@ class DerivativesDataSink(SimpleInterface):
276276
>>> res.outputs.out_file # doctest: +ELLIPSIS
277277
'.../niworkflows/sub-01/ses-retest/anat/sub-01_ses-retest_desc-denoised_T1w.nii.gz'
278278
279+
>>> dsink = DerivativesDataSink(base_directory=str(tmpdir), check_hdr=False,
280+
... allowed_entities=['from', 'to'], **{'from': 'orig'})
281+
>>> dsink.inputs.in_file = str(tmpfile)
282+
>>> dsink.inputs.to = 'native'
283+
>>> dsink.inputs.source_file = bids_collect_data(
284+
... str(datadir / 'ds114'), '01', bids_validate=False)[0]['t1w'][0]
285+
>>> dsink.inputs.keep_dtype = True
286+
>>> res = dsink.run()
287+
>>> res.outputs.out_file # doctest: +ELLIPSIS
288+
'.../sub-01_ses-retest_from-orig_to-native_T1w.nii.gz'
289+
279290
>>> bids_dir = tmpdir / 'bidsroot' / 'sub-02' / 'ses-noanat' / 'func'
280291
>>> bids_dir.mkdir(parents=True, exist_ok=True)
281292
>>> tricky_source = bids_dir / 'sub-02_ses-noanat_task-rest_run-01_bold.nii.gz'
@@ -364,13 +375,20 @@ class DerivativesDataSink(SimpleInterface):
364375
out_path_base = "niworkflows"
365376
_always_run = True
366377

367-
def __init__(self, out_path_base=None, **inputs):
378+
def __init__(self, allowed_entities=None, out_path_base=None, **inputs):
379+
self._allowed_entities = allowed_entities or []
380+
368381
self._metadata = {}
369-
self._static_traits = self.input_spec.class_editable_traits()
382+
self._static_traits = self.input_spec.class_editable_traits() + self._allowed_entities
370383
for dynamic_input in set(inputs) - set(self._static_traits):
371384
self._metadata[dynamic_input] = inputs.pop(dynamic_input)
372385

373386
super(DerivativesDataSink, self).__init__(**inputs)
387+
if self._allowed_entities:
388+
add_traits(self.inputs, self._allowed_entities)
389+
for k in set(self._allowed_entities).intersection(list(inputs.keys())):
390+
setattr(self.inputs, k, inputs[k])
391+
374392
self._results['out_file'] = []
375393
if out_path_base:
376394
self.out_path_base = out_path_base
@@ -409,9 +427,18 @@ def _run_interface(self, runtime):
409427
out_path.mkdir(exist_ok=True, parents=True)
410428
base_fname = str(out_path / src_fname)
411429

412-
formatstr = '{bname}{space}{desc}{extra}{suffix}{dtype}{ext}'
430+
allowed_entities = {}
431+
for key in self._allowed_entities:
432+
value = getattr(self.inputs, key)
433+
if value is not None and isdefined(value):
434+
allowed_entities[key] = '_%s-%s' % (key, value)
435+
436+
formatbase = '{bname}{space}{desc}' + ''.join(
437+
[allowed_entities.get(s, '') for s in self._allowed_entities])
438+
439+
formatstr = formatbase + '{extra}{suffix}{dtype}{ext}'
413440
if len(self.inputs.in_file) > 1 and not isdefined(self.inputs.extra_values):
414-
formatstr = '{bname}{space}{desc}{suffix}{i:04d}{dtype}{ext}'
441+
formatstr = formatbase + '{suffix}{i:04d}{dtype}{ext}'
415442

416443
space = '_space-{}'.format(self.inputs.space) if self.inputs.space else ''
417444
desc = '_desc-{}'.format(self.inputs.desc) if self.inputs.desc else ''
@@ -420,6 +447,7 @@ def _run_interface(self, runtime):
420447

421448
self._results['compression'] = []
422449
self._results['fixed_hdr'] = [False] * len(self.inputs.in_file)
450+
423451
for i, fname in enumerate(self.inputs.in_file):
424452
extra = ''
425453
if isdefined(self.inputs.extra_values):

0 commit comments

Comments
 (0)