Skip to content

Commit e81839f

Browse files
committed
enh: make some init methods classmethods
1 parent a0cdd84 commit e81839f

File tree

6 files changed

+95
-101
lines changed

6 files changed

+95
-101
lines changed

docs/api.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ Internal configuration system
77
-----------------------------
88

99
.. automodule:: fmriprep.config
10-
:members: from_dict, load, get, dumps, to_filename, init_layout, init_spaces
10+
:members: from_dict, load, get, dumps, to_filename, init_spaces
1111

1212
Workflows
1313
---------

fmriprep/cli/parser.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -308,8 +308,7 @@ def parse_args(args=None, namespace=None):
308308
opts = parser.parse_args(args, namespace)
309309
config.execution.log_level = int(max(25 - 5 * opts.verbose_count, logging.DEBUG))
310310
config.from_dict(vars(opts))
311-
312-
config.init_loggers()
311+
config.loggers.init()
313312

314313
# Retrieve logging level
315314
build_log = config.loggers.cli
@@ -388,8 +387,8 @@ def parse_args(args=None, namespace=None):
388387
output_dir.mkdir(exist_ok=True, parents=True)
389388
work_dir.mkdir(exist_ok=True, parents=True)
390389

391-
# First check that bids_dir looks like a BIDS folder
392-
config.init_layout()
390+
# Force initialization of the BIDSLayout
391+
config.execution.init()
393392
all_subjects = config.execution.layout.get_subjects()
394393
if config.execution.participant_label is None:
395394
config.execution.participant_label = all_subjects

fmriprep/cli/workflow.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ def build_workflow(config_file, retval):
4242
config.execution.bids_description_hash = sha256(desc_content).hexdigest()
4343

4444
# First check that bids_dir looks like a BIDS folder
45-
config.init_layout()
4645
subject_list = collect_participants(
4746
config.execution.layout,
4847
participant_label=config.execution.participant_label

fmriprep/config.py

Lines changed: 84 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,11 @@
116116
----------------------
117117
The :py:mod:`config` is responsible for other conveniency actions.
118118
119-
* Switching Python's ``multiprocessing`` to *forkserver* mode.
119+
* Switching Python's :obj:`multiprocessing` to *forkserver* mode.
120120
* Set up a filter for warnings as early as possible.
121-
* Automated I/O magic operations:
122-
123-
* :obj:`Path` \<-\> :obj:`str` \<-\> :obj:`Path`).
124-
* :py:class:`~niworkflows.util.spaces.SpatialReferences` \<-\> :obj:`str` \<-\>
125-
:py:class:`~niworkflows.util.spaces.SpatialReferences`
126-
* :py:class:`~bids.layout.BIDSLayout` \<-\> :obj:`str` \<-\>
127-
:py:class:`~bids.layout.BIDSLayout`
121+
* Automated I/O magic operations. Some conversions need to happen in the
122+
store/load processes (e.g., from/to :obj:`~pathlib.Path` \<-\> :obj:`str`,
123+
:py:class:`~bids.layout.BIDSLayout`, etc.)
128124
129125
"""
130126
from multiprocessing import set_start_method
@@ -229,7 +225,7 @@ def __init__(self):
229225
raise RuntimeError('Configuration type is not instantiable.')
230226

231227
@classmethod
232-
def load(cls, settings):
228+
def load(cls, settings, init=True):
233229
"""Store settings from a dictionary."""
234230
for k, v in settings.items():
235231
if v is None:
@@ -240,6 +236,12 @@ def load(cls, settings):
240236
if hasattr(cls, k):
241237
setattr(cls, k, v)
242238

239+
if init:
240+
try:
241+
cls.init()
242+
except AttributeError:
243+
pass
244+
243245
@classmethod
244246
def get(cls):
245247
"""Return defined settings."""
@@ -331,6 +333,32 @@ def get_plugin(cls):
331333
out['plugin_args']['memory_gb'] = float(cls.memory_gb)
332334
return out
333335

336+
@classmethod
337+
def init(cls):
338+
"""Set NiPype configurations."""
339+
from nipype import config as ncfg
340+
341+
# Configure resource_monitor
342+
if cls.resource_monitor:
343+
ncfg.update_config({
344+
'monitoring': {
345+
'enabled': cls.resource_monitor,
346+
'sample_frequency': '0.5',
347+
'summary_append': True,
348+
}
349+
})
350+
ncfg.enable_resource_monitor()
351+
352+
# Nipype config (logs and execution)
353+
ncfg.update_config({
354+
'execution': {
355+
'crashdump_dir': str(execution.log_dir),
356+
'crashfile_format': cls.crashfile_format,
357+
'get_linked_libs': cls.get_linked_libs,
358+
'stop_on_first_crash': cls.stop_on_first_crash,
359+
}
360+
})
361+
334362

335363
class execution(_Config):
336364
"""Configure run-level settings."""
@@ -352,8 +380,7 @@ class execution(_Config):
352380
fs_subjects_dir = None
353381
"""FreeSurfer's subjects directory."""
354382
layout = None
355-
"""A py:class:`~bids.layout.BIDSLayout` object, see
356-
:py:func:`~fmriprep.config.init_layout`."""
383+
"""A :py:class:`~bids.layout.BIDSLayout` object, see :py:func:`init`."""
357384
log_dir = None
358385
"""The path to a directory that contains execution logs."""
359386
log_level = 25
@@ -397,6 +424,22 @@ class execution(_Config):
397424
'work_dir',
398425
)
399426

427+
@classmethod
428+
def init(cls):
429+
"""Create a new BIDS Layout accessible with :attr:`~execution.layout`."""
430+
if cls._layout is None:
431+
import re
432+
from bids.layout import BIDSLayout
433+
work_dir = cls.work_dir / 'bids.db'
434+
work_dir.mkdir(exist_ok=True, parents=True)
435+
cls._layout = BIDSLayout(
436+
str(cls.bids_dir),
437+
validate=False,
438+
# database_path=str(work_dir),
439+
ignore=("code", "stimuli", "sourcedata", "models",
440+
"derivatives", re.compile(r'^\.')))
441+
cls.layout = cls._layout
442+
400443

401444
# These variables are not necessary anymore
402445
del _fs_license
@@ -467,18 +510,7 @@ class workflow(_Config):
467510

468511

469512
class loggers:
470-
"""
471-
Setup loggers, providing access to them across the *fMRIPrep* run.
472-
473-
* Add new logger levels (25: IMPORTANT, and 15: VERBOSE).
474-
* Add a new sub-logger (``cli``).
475-
* Logger configuration.
476-
477-
See also:
478-
479-
.. autofunction: init_loggers
480-
481-
"""
513+
"""Keep loggers easily accessible (see :py:func:`init`)."""
482514

483515
_fmt = "%(asctime)s,%(msecs)d %(name)-2s " "%(levelname)-2s:\n\t %(message)s"
484516
_datefmt = "%y%m%d-%H:%M:%S"
@@ -494,13 +526,41 @@ class loggers:
494526
utils = nlogging.getLogger('nipype.utils')
495527
"""NiPype's utils logger."""
496528

529+
@classmethod
530+
def init(cls):
531+
"""
532+
Set the log level, initialize all loggers into :py:class:`loggers`.
533+
534+
* Add new logger levels (25: IMPORTANT, and 15: VERBOSE).
535+
* Add a new sub-logger (``cli``).
536+
* Logger configuration.
537+
538+
"""
539+
from nipype import config as ncfg
540+
_handler = logging.StreamHandler(stream=sys.stdout)
541+
_handler.setFormatter(
542+
logging.Formatter(fmt=cls._fmt, datefmt=cls._datefmt)
543+
)
544+
cls.cli.addHandler(_handler)
545+
cls.default.setLevel(execution.log_level)
546+
cls.cli.setLevel(execution.log_level)
547+
cls.interface.setLevel(execution.log_level)
548+
cls.workflow.setLevel(execution.log_level)
549+
cls.utils.setLevel(execution.log_level)
550+
ncfg.update_config({
551+
'logging': {
552+
'log_directory': str(execution.log_dir),
553+
'log_to_file': True
554+
},
555+
})
556+
497557

498558
def from_dict(settings):
499559
"""Read settings from a flat dictionary."""
500560
nipype.load(settings)
501561
execution.load(settings)
502562
workflow.load(settings)
503-
init_loggers()
563+
loggers.init()
504564

505565

506566
def load(filename):
@@ -512,10 +572,7 @@ def load(filename):
512572
if sectionname != 'environment':
513573
section = getattr(sys.modules[__name__], sectionname)
514574
section.load(configs)
515-
init_nipype()
516-
init_loggers()
517575
init_spaces()
518-
init_layout()
519576

520577

521578
def get(flat=False):
@@ -546,43 +603,6 @@ def to_filename(filename):
546603
filename.write_text(dumps())
547604

548605

549-
def init_layout():
550-
"""Create a new BIDS Layout accessible with :attr:`~execution.layout`."""
551-
if execution._layout is None:
552-
import re
553-
from bids.layout import BIDSLayout
554-
work_dir = execution.work_dir / 'bids.db'
555-
work_dir.mkdir(exist_ok=True, parents=True)
556-
execution._layout = BIDSLayout(
557-
str(execution.bids_dir),
558-
validate=False,
559-
# database_path=str(work_dir),
560-
ignore=("code", "stimuli", "sourcedata", "models",
561-
"derivatives", re.compile(r'^\.')))
562-
execution.layout = execution._layout
563-
564-
565-
def init_loggers():
566-
"""Set the current log level to all loggers."""
567-
from nipype import config as ncfg
568-
_handler = logging.StreamHandler(stream=sys.stdout)
569-
_handler.setFormatter(
570-
logging.Formatter(fmt=loggers._fmt, datefmt=loggers._datefmt)
571-
)
572-
loggers.cli.addHandler(_handler)
573-
loggers.default.setLevel(execution.log_level)
574-
loggers.cli.setLevel(execution.log_level)
575-
loggers.interface.setLevel(execution.log_level)
576-
loggers.workflow.setLevel(execution.log_level)
577-
loggers.utils.setLevel(execution.log_level)
578-
ncfg.update_config({
579-
'logging': {
580-
'log_directory': str(execution.log_dir),
581-
'log_to_file': True
582-
},
583-
})
584-
585-
586606
def init_spaces(checkpoint=True):
587607
"""Initialize the :attr:`~workflow.spaces` setting."""
588608
from niworkflows.utils.spaces import Reference, SpatialReferences
@@ -624,29 +644,3 @@ def init_spaces(checkpoint=True):
624644

625645
# Make the SpatialReferences object available
626646
workflow.spaces = spaces
627-
628-
629-
def init_nipype():
630-
"""Set NiPype configurations."""
631-
from nipype import config as ncfg
632-
633-
# Configure resource_monitor
634-
if nipype.resource_monitor:
635-
ncfg.update_config({
636-
'monitoring': {
637-
'enabled': nipype.resource_monitor,
638-
'sample_frequency': '0.5',
639-
'summary_append': True,
640-
}
641-
})
642-
ncfg.enable_resource_monitor()
643-
644-
# Nipype config (logs and execution)
645-
ncfg.update_config({
646-
'execution': {
647-
'crashdump_dir': str(execution.log_dir),
648-
'crashfile_format': nipype.crashfile_format,
649-
'get_linked_libs': nipype.get_linked_libs,
650-
'stop_on_first_crash': nipype.stop_on_first_crash,
651-
}
652-
})

fmriprep/tests/test_config.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,9 @@ def test_config_spaces():
1414
for sectionname, configs in settings.items():
1515
if sectionname != 'environment':
1616
section = getattr(config, sectionname)
17-
section.load(configs)
18-
config.init_loggers()
17+
section.load(configs, init=False)
18+
config.nipype.init()
19+
config.loggers.init()
1920
config.init_spaces()
2021

2122
spaces = config.workflow.spaces

fmriprep/workflows/tests.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,14 @@ def mock_config():
2020
for sectionname, configs in settings.items():
2121
if sectionname != 'environment':
2222
section = getattr(config, sectionname)
23-
section.load(configs)
24-
config.init_loggers()
23+
section.load(configs, init=False)
24+
config.nipype.init()
25+
config.loggers.init()
2526
config.init_spaces()
2627

2728
config.execution.work_dir = Path(mkdtemp())
2829
config.execution.bids_dir = Path(pkgrf('fmriprep', 'data/tests/ds000005')).absolute()
29-
config.init_layout()
30+
config.execution.init()
3031

3132
yield
3233

0 commit comments

Comments
 (0)