1- # Copyright (C) 2022-2024 C-PAC Developers
1+ # Copyright (C) 2022-2025 C-PAC Developers
22
33# This file is part of C-PAC.
44
2424from traceback import print_exception
2525from typing import Literal , Optional , Sequence , TYPE_CHECKING , TypeAlias
2626
27+ import yaml
2728from nipype import config as nipype_config , logging as nipype_logging
2829
2930from CPAC .utils .docs import docstring_parameter
@@ -163,6 +164,22 @@ def log_subprocess(cmd, *args, raise_error=True, **kwargs):
163164 return output , 0
164165
165166
167+ class ListToSetYamlLoader (yaml .Loader ):
168+ """Custom YAML loader to convert lists to sets."""
169+
170+ def construct_sequence ( # pyright: ignore[reportIncompatibleMethodOverride]
171+ self , node , deep = False
172+ ) -> set [str ]:
173+ """Convert YAML sequence to a set."""
174+ return set (super ().construct_sequence (node , deep ))
175+
176+
177+ ListToSetYamlLoader .add_constructor (
178+ yaml .resolver .BaseResolver .DEFAULT_SEQUENCE_TAG ,
179+ ListToSetYamlLoader .construct_sequence ,
180+ )
181+
182+
166183# pylint: disable=too-few-public-methods
167184class MockHandler :
168185 """Handler for MockLogger."""
@@ -233,6 +250,24 @@ def _get_first_file_handler(
233250 return handler
234251 return None
235252
253+ def yaml_contents (self ) -> dict :
254+ """If the logger's first handler is a YAML file, return the contents and delete them from the logger."""
255+ file = self ._get_first_file_handler (self .handlers )
256+ if hasattr (file , "baseFilename" ):
257+ file = Path (getattr (file , "baseFilename" ))
258+ if file .suffix == ".yml" :
259+ with file .open ("r" , encoding = "utf-8" ) as f :
260+ contents = yaml .load (f .read (), Loader = ListToSetYamlLoader )
261+ with file .open ("w" , encoding = "utf-8" ) as f :
262+ f .write ("" )
263+ return contents
264+ error = TypeError
265+ msg = f"Could not load YAML contents from { file } "
266+ else :
267+ error = FileNotFoundError
268+ msg = f"Could not find file handler for { self .name } "
269+ raise error (msg )
270+
236271
237272def _lazy_sub (message , * items ):
238273 """Given lazy-logging syntax, return string with substitutions.
@@ -268,7 +303,6 @@ def set_up_logger(
268303 level : Optional [LogLevel ] = None ,
269304 log_dir : Optional [Path | str ] = None ,
270305 mock : bool = False ,
271- overwrite_existing : bool = False ,
272306) -> logging .Logger | MockLogger :
273307 r"""Initialize a logger.
274308
@@ -328,9 +362,6 @@ def set_up_logger(
328362 level = logging .NOTSET
329363 log_dir = Path (log_dir ) if log_dir else Path .cwd ()
330364 filepath = log_dir / filename
331- if overwrite_existing and filepath .exists ():
332- with filepath .open ("w" , encoding = "utf-8" ) as log_file :
333- log_file .write ("" )
334365 if not filepath .exists ():
335366 filepath .parent .mkdir (parents = True , exist_ok = True )
336367 if mock :
@@ -356,16 +387,12 @@ def init_loggers(
356387
357388 if "subject_id" not in cpac_config :
358389 cpac_config ["subject_id" ] = subject_id
359-
360390 set_up_logger (
361- f"{ subject_id } _expectedOutputs" ,
391+ f"{ cpac_config [ ' subject_id' ] } _expectedOutputs" ,
362392 filename = f"{ bidsier_prefix (cpac_config ['subject_id' ])} _expectedOutputs.yml" ,
363393 level = "info" ,
364394 log_dir = log_dir ,
365395 mock = mock ,
366- overwrite_existing = ( # don't overwrite if we have a longitudinal template
367- longitudinal or not cpac_config ["longitudinal_template_generation" , "run" ]
368- ),
369396 )
370397
371398 if cpac_config ["pipeline_setup" , "Debugging" , "verbose" ]:
0 commit comments