Skip to content

Commit 51d1a96

Browse files
committed
ENH: Autopopulate subjects and sessions for populate-intended-for\n\nwhen not specified in call to main
1 parent 961fd83 commit 51d1a96

File tree

2 files changed

+60
-6
lines changed

2 files changed

+60
-6
lines changed

heudiconv/main.py

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import logging
22
import os.path as op
33
import sys
4+
from glob import glob
45

56
from . import __version__, __packagename__
67
from .bids import populate_bids_templates, tuneup_bids_json_files, populate_intended_for
@@ -113,11 +114,42 @@ def process_extra_commands(outdir, command, files, dicom_dir_template,
113114
if heuristic:
114115
heuristic = load_heuristic(heuristic)
115116
kwargs = getattr(heuristic, 'POPULATE_INTENDED_FOR_OPTS', {})
117+
if not subjs:
118+
subjs = [
119+
# search outdir for 'sub-*'; if it is a directory (not a regular file), remove
120+
# the initial 'sub-':
121+
op.basename(s)[len('sub-'):] for s in glob(op.join(outdir, 'sub-*')) if op.isdir(s)
122+
]
123+
# read the subjects from the participants.tsv file to compare:
124+
participants_tsv = op.join(outdir, 'participants.tsv')
125+
if op.lexists(participants_tsv):
126+
with open(participants_tsv, 'r') as f:
127+
# read header line and find index for 'participant_id':
128+
participant_id_index = f.readline().split('\t').index('participant_id')
129+
# read all participants, removing the initial 'sub-':
130+
known_subjects = [
131+
l.split('\t')[participant_id_index][len('sub-'):] for l in f.readlines()
132+
]
133+
if not set(subjs) == set(known_subjects):
134+
# issue a warning, but continue with the 'subjs' list (the subjects for
135+
# which there is data):
136+
lgr.warning(
137+
"'participants.tsv' contents are not identical to subjects found "
138+
"in the BIDS dataset %s", outdir
139+
)
140+
116141
for subj in subjs:
117-
session_path = op.join(outdir, 'sub-' + subj)
142+
subject_path = op.join(outdir, 'sub-' + subj)
118143
if session:
119-
session_path = op.join(session_path, 'ses-' + session)
120-
populate_intended_for(session_path, **kwargs)
144+
session_paths = [op.join(subject_path, 'ses-' + session)]
145+
else:
146+
# check to see if the data for this subject is organized by sessions; if not
147+
# just use the subject_path
148+
session_paths = [
149+
s for s in glob(op.join(subject_path, 'ses-*')) if op.isdir(s)
150+
] or [subject_path]
151+
for session_path in session_paths:
152+
populate_intended_for(session_path, **kwargs)
121153
else:
122154
raise ValueError("Unknown command %s" % command)
123155
return

heudiconv/tests/test_main.py

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -313,11 +313,11 @@ def test_no_etelemetry():
313313
# The "expected_folder" is the session folder without the tmpdir
314314
@pytest.mark.parametrize(
315315
"session, expected_folder", [
316-
('', '/foo/sub-{sID}'),
317-
('pre', '/foo/sub-{sID}/ses-pre')
316+
('', 'foo/sub-{sID}'),
317+
('pre', 'foo/sub-{sID}/ses-pre')
318318
]
319319
)
320-
def test_populate_intended_for(session, expected_folder, capfd):
320+
def test_populate_intended_for(tmpdir, session, expected_folder, capfd):
321321
"""
322322
Tests for "process_extra_commands" when the command is
323323
'populate-intended-for'
@@ -336,3 +336,25 @@ def test_populate_intended_for(session, expected_folder, capfd):
336336
for s in subjects:
337337
expected_info = 'Adding "IntendedFor" to the fieldmaps in ' + expected_folder.format(sID=s)
338338
assert expected_info in captured_output
339+
340+
# try the same, but without specifying the subjects or the session.
341+
# the code in main should find any subject in the output folder and call
342+
# populate_intended_for on each of them (or for each of the sessions, if
343+
# the data for that subject is organized in sessions):
344+
# TODO: Add a 'participants.tsv' file with one of the subjects missing;
345+
# the 'process_extra_commands' call should print out a warning
346+
outdir = opj(str(tmpdir), bids_folder)
347+
for subj in subjects:
348+
subj_dir = opj(outdir, 'sub-' + subj)
349+
print('Creating output dir: %s', subj_dir)
350+
os.makedirs(subj_dir)
351+
if session:
352+
os.makedirs(opj(subj_dir, 'ses-' + session))
353+
process_extra_commands(outdir, 'populate-intended-for', [], '',
354+
'example', [], [], None)
355+
captured_output = capfd.readouterr().err
356+
for s in subjects:
357+
expected_info = 'Adding "IntendedFor" to the fieldmaps in ' + opj(str(tmpdir), expected_folder.format(sID=s))
358+
assert expected_info in captured_output
359+
360+

0 commit comments

Comments
 (0)