1515from 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-
5718def 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