@@ -279,7 +279,8 @@ class _DerivativesDataSinkInputSpec(DynamicTraitedSpec, BaseInterfaceInputSpec):
279279 File (exists = True ), mandatory = True , desc = "the object to be saved"
280280 )
281281 meta_dict = traits .DictStrAny (desc = "an input dictionary containing metadata" )
282- source_file = File (exists = False , mandatory = True , desc = "the input func file" )
282+ source_file = InputMultiObject (
283+ File (exists = False ), mandatory = True , desc = "the source file(s) to extract entities from" )
283284
284285
285286class _DerivativesDataSinkOutputSpec (TraitedSpec ):
@@ -348,6 +349,32 @@ class DerivativesDataSink(SimpleInterface):
348349 ['.../niworkflows/sub-01/ses-retest/anat/sub-01_ses-retest_custom1-1_custom2-b_T1w.nii',
349350 '.../niworkflows/sub-01/ses-retest/anat/sub-01_ses-retest_custom1-2_custom2-b_T1w.nii']
350351
352+ When multiple source files are passed, only common entities are passed down.
353+ For example, if two T1w images from different sessions are used to generate
354+ a single image, the session entity is removed automatically.
355+
356+ >>> bids_dir = tmpdir / 'bidsroot'
357+ >>> multi_source = [
358+ ... bids_dir / 'sub-02/ses-A/anat/sub-02_ses-A_T1w.nii.gz',
359+ ... bids_dir / 'sub-02/ses-B/anat/sub-02_ses-B_T1w.nii.gz']
360+ >>> for source_file in multi_source:
361+ ... source_file.parent.mkdir(parents=True, exist_ok=True)
362+ ... _ = source_file.write_text("")
363+ >>> dsink = DerivativesDataSink(base_directory=str(tmpdir), check_hdr=False)
364+ >>> dsink.inputs.in_file = str(tmpfile)
365+ >>> dsink.inputs.source_file = list(map(str, multi_source))
366+ >>> dsink.inputs.desc = 'preproc'
367+ >>> res = dsink.run()
368+ >>> res.outputs.out_file # doctest: +ELLIPSIS
369+ '.../niworkflows/sub-02/anat/sub-02_desc-preproc_T1w.nii'
370+
371+ If, on the other hand, only one is used, the session is preserved:
372+
373+ >>> dsink.inputs.source_file = str(multi_source[0])
374+ >>> res = dsink.run()
375+ >>> res.outputs.out_file # doctest: +ELLIPSIS
376+ '.../niworkflows/sub-02/ses-A/anat/sub-02_ses-A_desc-preproc_T1w.nii'
377+
351378 >>> bids_dir = tmpdir / 'bidsroot' / 'sub-02' / 'ses-noanat' / 'func'
352379 >>> bids_dir.mkdir(parents=True, exist_ok=True)
353380 >>> tricky_source = bids_dir / 'sub-02_ses-noanat_task-rest_run-01_bold.nii.gz'
@@ -480,9 +507,12 @@ def _run_interface(self, runtime):
480507 self ._metadata = meta
481508
482509 # Initialize entities with those from the source file.
483- out_entities = parse_file_entities (
484- str (relative_to_root (self .inputs .source_file ))
485- )
510+ in_entities = [
511+ parse_file_entities (str (relative_to_root (source_file )))
512+ for source_file in self .inputs .source_file
513+ ]
514+ out_entities = {k : v for k , v in in_entities [0 ].items ()
515+ if all (ent .get (k ) == v for ent in in_entities [1 :])}
486516 for drop_entity in listify (self .inputs .dismiss_entities or []):
487517 out_entities .pop (drop_entity , None )
488518
0 commit comments