Skip to content

Commit 1cb1e1c

Browse files
committed
De-duplicate code for parsing personal / participants data
1 parent 0d2293c commit 1cb1e1c

File tree

1 file changed

+22
-46
lines changed

1 file changed

+22
-46
lines changed

bidscoin/utilities/bidsparticipants.py

Lines changed: 22 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -15,45 +15,6 @@
1515
from bidscoin.utilities import unpack
1616

1717

18-
def scanpersonals(bidsmap: BidsMap, session: Path, personals: dict, keys: list) -> bool:
19-
"""
20-
Converts the session source-files into BIDS-valid NIfTI-files in the corresponding bidsfolder and
21-
extracts personals (e.g. Age, Sex) from the source header
22-
23-
:param bidsmap: The study bidsmap with the mapping heuristics
24-
:param session: The full-path name of the subject/session source file/folder
25-
:param personals: The dictionary with the personal information
26-
:param keys: The keys that are extracted from the source data when populating the participants.tsv file
27-
:return: True if successful
28-
"""
29-
30-
# Get valid BIDS subject/session identifiers from the (first) DICOM- or PAR/XML source file
31-
datasource = bids.get_datasource(session, bidsmap.plugins)
32-
dataformat = datasource.dataformat
33-
if not datasource.dataformat:
34-
LOGGER.info(f"No supported datasource found in '{session}'")
35-
return False
36-
37-
# Collect personal data from a source header (PAR/XML does not contain personal info)
38-
if dataformat not in ('DICOM', 'Twix'): return False
39-
40-
if 'sex' in keys: personals['sex'] = datasource.attributes('PatientSex')
41-
if 'size' in keys: personals['size'] = datasource.attributes('PatientSize')
42-
if 'weight' in keys: personals['weight'] = datasource.attributes('PatientWeight')
43-
if 'age' in keys:
44-
age = datasource.attributes('PatientAge') # A string of characters with one of the following formats: nnnD, nnnW, nnnM, nnnY
45-
if age.endswith('D'): age = float(age.rstrip('D')) / 365.2524
46-
elif age.endswith('W'): age = float(age.rstrip('W')) / 52.1775
47-
elif age.endswith('M'): age = float(age.rstrip('M')) / 12
48-
elif age.endswith('Y'): age = float(age.rstrip('Y'))
49-
if age:
50-
if bidsmap.options.get('anon','y') in ('y','yes'):
51-
age = int(float(age))
52-
personals['age'] = str(age)
53-
54-
return True
55-
56-
5718
def bidsparticipants(sourcefolder: str, bidsfolder: str, keys: list, bidsmap: str= 'bidsmap.yaml', dryrun: bool=False) -> None:
5819
"""
5920
Main function that processes all the subjects and session in the sourcefolder to (re)generate the participants.tsv file in the BIDS folder.
@@ -105,6 +66,9 @@ def bidsparticipants(sourcefolder: str, bidsfolder: str, keys: list, bidsmap: st
10566
if participant not in [sub.name for sub in subjects]:
10667
participants_table.drop(participant, inplace=True)
10768

69+
# Import the plugins
70+
plugins = [plugin for name in bidsmap.plugins if (plugin := bcoin.import_plugin(name))]
71+
10872
# Loop over all subjects in the bids-folder and add them to the participants table
10973
with logging_redirect_tqdm():
11074
for n, subject in enumerate(tqdm(subjects, unit='subject', colour='green', leave=False), 1):
@@ -127,16 +91,28 @@ def bidsparticipants(sourcefolder: str, bidsfolder: str, keys: list, bidsmap: st
12791
sesfolders, unpacked = unpack(session, bidsmap.options.get('unzip',''))
12892
for sesfolder in sesfolders:
12993

130-
# Update/append the personal source data
131-
LOGGER.info(f"Scanning session: {sesfolder}")
132-
success = scanpersonals(bidsmap, sesfolder, personals, keys)
94+
# Run the plugin.Interface().personals()
95+
for plugin in plugins:
13396

134-
# Clean-up the temporary unpacked data
135-
if unpacked:
136-
shutil.rmtree(sesfolder)
97+
name = Path(plugin.__file__).stem
98+
datasource = bids.get_datasource(sesfolder, {name: bidsmap.plugins[name]})
99+
if not datasource.dataformat:
100+
LOGGER.info(f">>> No {name} datasources found in '{sesfolder}'")
101+
continue
137102

138-
if success: break
103+
# Update/append the personal source data
104+
LOGGER.info(f"Scanning session: {sesfolder}")
105+
personaldata = plugin.Interface().personals(bidsmap, datasource)
106+
if personaldata:
107+
personals.update(personaldata)
108+
success = True
139109

110+
# Clean-up the temporary unpacked data
111+
if unpacked:
112+
shutil.rmtree(sesfolder)
113+
114+
if success: break
115+
if success: break
140116
if success: break
141117

142118
# Store the collected personals in the participant_table. TODO: Check that only values that are consistent over sessions go in the participants.tsv file, otherwise put them in a sessions.tsv file

0 commit comments

Comments
 (0)