@@ -127,34 +127,44 @@ def _link_or_copy(src_path, dst_path):
127127 if not os .path .exists (subject_folder_path ):
128128 os .makedirs (subject_folder_path , exist_ok = True )
129129
130- # Ensure participants.tsv is available in temp root and is a copy (not a link)
131- # Always COPY (never link) to avoid modifying the original file when filtering
132- participants_tsv_path = os .path .join (temporary_bids_dir , "participants.tsv" )
133- # Always remove existing file first in case it was linked in the earlier loop
134- if os .path .exists (participants_tsv_path ):
130+ # Ensure participants.tsv and participants.json are available in temp root
131+ # Always COPY (never link) to avoid modifying the original files when filtering
132+ participants_files = ["participants.tsv" , "participants.json" ]
133+ for filename in participants_files :
134+ dest_path = os .path .join (temporary_bids_dir , filename )
135+ # Always remove existing file first in case it was linked in the earlier loop
136+ if os .path .exists (dest_path ):
137+ try :
138+ os .remove (dest_path )
139+ except Exception as e :
140+ logger .warning (
141+ f"Failed to remove existing file '{ dest_path } ': { e } . "
142+ "The file may be overwritten or cause conflicts."
143+ )
144+ # Try to find source file in the provided file list
135145 try :
136- os .remove (participants_tsv_path )
137- except Exception : # noqa: BLE001
138- pass
139- # Try to find a source participants.tsv in the provided file list
140- try :
141- source_participants_tsv_path = None
142- for candidate_path in files_list :
143- if os .path .basename (candidate_path ) == "participants.tsv" :
144- source_participants_tsv_path = candidate_path
145- break
146- # If not in file list, try to get it from the original bids_dir
147- if not source_participants_tsv_path and bids_dir :
148- potential_path = os .path .join (bids_dir , "participants.tsv" )
149- if os .path .exists (potential_path ):
150- source_participants_tsv_path = potential_path
151- if source_participants_tsv_path :
152- # Always copy (not link) to protect the original file from modification
153- shutil .copy2 (source_participants_tsv_path , participants_tsv_path )
154- except Exception : # noqa: BLE001
155- pass
146+ source_path = None
147+ for candidate_path in files_list :
148+ if os .path .basename (candidate_path ) == filename :
149+ source_path = candidate_path
150+ break
151+ # If not in file list, try to get it from the original bids_dir
152+ if not source_path and bids_dir :
153+ potential_path = os .path .join (bids_dir , filename )
154+ if os .path .exists (potential_path ):
155+ source_path = potential_path
156+ if source_path :
157+ # Always copy (not link) to protect the original file from modification
158+ shutil .copy2 (source_path , dest_path )
159+ except Exception as e :
160+ source_info = source_path if source_path else "unknown location"
161+ logger .warning (
162+ f"Failed to copy '{ filename } ' from '{ source_info } ' to '{ dest_path } ': { e } . "
163+ "The file may be missing or inaccessible."
164+ )
156165
157166 # If participants.tsv exists in the temp BIDS root, filter to current subject
167+ participants_tsv_path = os .path .join (temporary_bids_dir , "participants.tsv" )
158168 if os .path .exists (participants_tsv_path ):
159169 try :
160170 participants_table = pd .read_csv (participants_tsv_path , sep = "\t " )
@@ -166,10 +176,13 @@ def _link_or_copy(src_path, dst_path):
166176 participants_tsv_path ,
167177 sep = "\t " ,
168178 index = False ,
179+ na_rep = "n/a" ,
169180 )
170- except Exception as e : # noqa: F841
171- # Non-fatal: continue validation even if filtering fails
172- pass
181+ except Exception as e :
182+ logger .warning (
183+ f"Failed to filter participants.tsv for subject { subject } : { e } . "
184+ "Continuing validation without filtering."
185+ )
173186
174187 # Run the validator
175188 call = build_validator_call (
@@ -271,7 +284,7 @@ def validate(
271284 else :
272285 val_tsv = str (bids_dir ) + "/code/CuBIDS/" + str (output_prefix ) + "_validation.tsv"
273286
274- parsed .to_csv (val_tsv , sep = "\t " , index = False )
287+ parsed .to_csv (val_tsv , sep = "\t " , index = False , na_rep = "n/a" )
275288
276289 # build validation data dictionary json sidecar
277290 val_dict = get_val_dictionary ()
@@ -363,7 +376,7 @@ def validate(
363376 else :
364377 val_tsv = str (bids_dir ) + "/code/CuBIDS/" + str (output_prefix ) + "_validation.tsv"
365378
366- parsed .to_csv (val_tsv , sep = "\t " , index = False )
379+ parsed .to_csv (val_tsv , sep = "\t " , index = False , na_rep = "n/a" )
367380
368381 # build validation data dictionary json sidecar
369382 val_dict = get_val_dictionary ()
@@ -487,6 +500,7 @@ def apply(
487500 edited_summary_tsv ,
488501 files_tsv ,
489502 new_tsv_prefix ,
503+ n_cpus = 1 ,
490504):
491505 """Apply the tsv changes.
492506
@@ -525,6 +539,7 @@ def apply(
525539 str (files_tsv ),
526540 str (new_tsv_prefix ),
527541 raise_on_error = False ,
542+ n_cpus = n_cpus ,
528543 )
529544
530545
0 commit comments