Skip to content

Commit d51977a

Browse files
committed
enh(doc): better documentation of the config object
1 parent 3e7a791 commit d51977a

File tree

5 files changed

+99
-48
lines changed

5 files changed

+99
-48
lines changed

docs/api.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,11 @@
33
================
44
Developers - API
55
================
6-
76
Internal configuration system
87
-----------------------------
98

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

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

fmriprep/cli/parser.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ def parse_args(args=None, namespace=None):
309309
config.execution.log_level = int(max(25 - 5 * opts.verbose_count, logging.DEBUG))
310310
config.from_dict(vars(opts))
311311

312-
config.set_logger_level()
312+
config.init_loggers()
313313

314314
# Retrieve logging level
315315
build_log = config.loggers.cli

fmriprep/config.py

Lines changed: 95 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,15 @@
11
# emacs: -*- mode: python; py-indent-offset: 4; indent-tabs-mode: nil -*-
22
# vi: set ft=python sts=4 ts=4 sw=4 et:
33
r"""
4-
*fMRIPrep* settings.
4+
A Python module to maintain unique, run-wide *fMRIPrep* settings.
55
66
This module implements the memory structures to keep a consistent, singleton config.
7-
8-
Example
9-
-------
10-
11-
.. code-block:: Python
12-
13-
from fmriprep import config
14-
config_file = config.execution.work_dir / '.fmriprep.toml'
15-
config.to_filename(config_file)
16-
# Call build_workflow(config_file, retval) in a subprocess
17-
with Manager() as mgr:
18-
from .workflow import build_workflow
19-
retval = mgr.dict()
20-
p = Process(target=build_workflow, args=(str(config_file), retval))
21-
p.start()
22-
p.join()
23-
config.load(config_file)
24-
# Access configs from any code section as:
25-
value = config.section.setting
26-
27-
The module also has a :py:func:`to_filename` function to allow writting out
28-
the settings to hard disk in *ToML* format, which looks like
7+
Settings are passed across processes via filesystem, and a copy of the settings for
8+
each run and subject is left under
9+
``<output_dir>/sub-<participant_id>/log/<run_unique_id>/fmriprep.toml``.
10+
Settings are stored using :abbr:`ToML (Tom's Markup Language)`.
11+
The module has a :py:func:`~fmriprep.config.to_filename` function to allow writting out
12+
the settings to hard disk in *ToML* format, which looks like:
2913
3014
.. code-block:: toml
3115
@@ -90,14 +74,50 @@
9074
raise_insufficient = false
9175
9276
This config file is used to pass the settings across processes,
93-
using the :py:func:`load` function.
77+
using the :py:func:`~fmriprep.config.load` function.
78+
79+
Configuration sections
80+
----------------------
81+
.. autoclass:: environment
82+
:members:
83+
.. autoclass:: execution
84+
:members:
85+
.. autoclass:: workflow
86+
:members:
87+
.. autoclass:: nipype
88+
:members:
89+
90+
Usage
91+
-----
92+
A config file is used to pass settings and collect information as the execution
93+
graph is built across processes.
94+
95+
.. code-block:: Python
96+
97+
from fmriprep import config
98+
config_file = config.execution.work_dir / '.fmriprep.toml'
99+
config.to_filename(config_file)
100+
# Call build_workflow(config_file, retval) in a subprocess
101+
with Manager() as mgr:
102+
from .workflow import build_workflow
103+
retval = mgr.dict()
104+
p = Process(target=build_workflow, args=(str(config_file), retval))
105+
p.start()
106+
p.join()
107+
config.load(config_file)
108+
# Access configs from any code section as:
109+
value = config.section.setting
110+
111+
Other responsibilities
112+
----------------------
113+
Logging
114+
.......
94115
95-
Other responsibilities of the config module:
116+
The :py:mod:`config` is responsible for other conveniency actions.
96117
97118
* Switching Python's ``multiprocessing`` to *forkserver* mode.
98-
* Set up new logger levels (25: IMPORTANT, and 15: VERBOSE).
99-
* Set up a warnings filter as soon as possible.
100-
* Initialize runtime descriptive settings (e.g., default FreeSurfer license,
119+
* Set up a filter for warnings as early as possible.
120+
* Initialize/crawl runtime descriptive settings (e.g., default FreeSurfer license,
101121
execution environment, nipype and *fMRIPrep* versions, etc.).
102122
* Automated I/O magic operations:
103123
@@ -241,7 +261,16 @@ def get(cls):
241261

242262

243263
class environment(_Config):
244-
"""Read-only options."""
264+
"""
265+
Read-only options regarding the platform and environment.
266+
267+
The ``environment`` section is not loaded in from file,
268+
only written out when settings are exported.
269+
This config section is useful when reporting issues,
270+
and these variables are tracked whenever the user does not
271+
opt-out using the ``--notrack`` argument.
272+
273+
"""
245274

246275
cpu_count = os.cpu_count()
247276
"""Number of available CPUs."""
@@ -264,7 +293,7 @@ class environment(_Config):
264293

265294

266295
class nipype(_Config):
267-
"""Nipype configuration."""
296+
"""Nipype settings."""
268297

269298
crashfile_format = 'txt'
270299
"""The file format for crashfiles, either text or pickle."""
@@ -303,10 +332,12 @@ def get_plugin(cls):
303332

304333

305334
class execution(_Config):
306-
"""Configure workflow-level settings."""
335+
"""Configure run-level settings."""
307336

308337
bids_dir = None
309-
"""An existing path to the dataset, which must be BIDS-compliant."""
338+
"""An existing path to the dataset, which must be BIDS-compliant.
339+
This config mutates to a :py:class:`~bids.layout.BIDSLayout` after calling
340+
:py:func:`~fmriprep.config.init_layout`."""
310341
bids_description_hash = None
311342
"""Checksum (SHA256) of the ``dataset_description.json`` of the BIDS dataset."""
312343
bids_filters = None
@@ -378,7 +409,7 @@ class execution(_Config):
378409

379410

380411
class workflow(_Config):
381-
"""Configure anatomical workflow."""
412+
"""Configure the particular execution graph of this workflow."""
382413

383414
anat_only = False
384415
"""Execute the anatomical preprocessing only."""
@@ -408,48 +439,68 @@ class workflow(_Config):
408439
longitudinal = False
409440
"""Run FreeSurfer ``recon-all`` with the ``-logitudinal`` flag."""
410441
medial_surface_nan = None
411-
"""Fill medial surface with NaNs (not-a-number) when sampling."""
442+
"""Fill medial surface with :abbr:`NaNs (not-a-number)` when sampling."""
412443
regressors_all_comps = None
444+
"""Return all CompCor components."""
413445
regressors_dvars_th = None
446+
"""Threshold for DVARS."""
414447
regressors_fd_th = None
448+
"""Threshold for :abbr:`FD (frame-wise displacement)`."""
415449
run_reconall = True
416450
"""Run FreeSurfer's surface reconstruction."""
417451
skull_strip_fixed_seed = False
418452
"""Fix a seed for skull-stripping."""
419-
skull_strip_template = 'OASIS30ANTs'
453+
skull_strip_template = "OASIS30ANTs"
420454
"""Change default brain extraction template."""
421455
spaces = None
422456
"""Standard and nonstandard spaces."""
423457
t2s_coreg = None
424-
r"""Co-register echos before generating the T2\* reference of ME-EPI."""
458+
"""Co-register echos before generating the T2\\* reference of \
459+
:abbr:`ME-EPI (multi-echo echo-planar imaging)`."""
425460
use_aroma = None
426461
"""Run ICA-AROMA."""
427462
use_bbr = None
428463
"""Run boundary-based registration for BOLD-to-T1w registration (default: ``True``)."""
429464
use_syn = None
430-
"""Run *fieldmap-less* susceptibility-derived distortions estimation
465+
"""Run *fieldmap-less* susceptibility-derived distortions estimation \
431466
in the absence of any alternatives."""
432467

433468

434469
class loggers(_Config):
435-
"""Configure 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+
"""
436482

437483
_fmt = "%(asctime)s,%(msecs)d %(name)-2s " "%(levelname)-2s:\n\t %(message)s"
438484
_datefmt = "%y%m%d-%H:%M:%S"
439485

440486
default = logging.getLogger()
487+
"""The root logger."""
441488
cli = logging.getLogger('cli')
489+
"""Command-line interface logging."""
442490
workflow = nlogging.getLogger('nipype.workflow')
491+
"""NiPype's workflow logger."""
443492
interface = nlogging.getLogger('nipype.interface')
493+
"""NiPype's interface logger."""
444494
utils = nlogging.getLogger('nipype.utils')
495+
"""NiPype's utils logger."""
445496

446497

447498
def from_dict(settings):
448499
"""Read settings from a flat dictionary."""
449500
nipype.load(settings)
450501
execution.load(settings)
451502
workflow.load(settings)
452-
set_logger_level()
503+
init_loggers()
453504

454505

455506
def load(filename):
@@ -461,7 +512,7 @@ def load(filename):
461512
if sectionname != 'environment':
462513
section = getattr(sys.modules[__name__], sectionname)
463514
section.load(configs)
464-
set_logger_level()
515+
init_loggers()
465516
init_spaces()
466517
init_layout()
467518

@@ -495,7 +546,7 @@ def to_filename(filename):
495546

496547

497548
def init_layout():
498-
"""Init a new layout."""
549+
"""Create a new BIDS Layout on :attr:`~execution.bids_dir`."""
499550
if execution._layout is None:
500551
import re
501552
from bids.layout import BIDSLayout
@@ -510,8 +561,8 @@ def init_layout():
510561
execution.layout = execution._layout
511562

512563

513-
def set_logger_level():
514-
"""Set the current log level to all nipype loggers."""
564+
def init_loggers():
565+
"""Set the current log level to all loggers."""
515566
_handler = logging.StreamHandler(stream=sys.stdout)
516567
_handler.setFormatter(
517568
logging.Formatter(fmt=loggers._fmt, datefmt=loggers._datefmt)
@@ -525,7 +576,7 @@ def set_logger_level():
525576

526577

527578
def init_spaces(checkpoint=True):
528-
"""Get a spatial references."""
579+
"""Initialize the :attr:`~workflow.spaces` setting."""
529580
from niworkflows.utils.spaces import Reference, SpatialReferences
530581
if (
531582
getattr(workflow, 'spaces')

fmriprep/tests/test_config.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ def test_config_spaces():
1515
if sectionname != 'environment':
1616
section = getattr(config, sectionname)
1717
section.load(configs)
18-
config.set_logger_level()
18+
config.init_loggers()
1919
config.init_spaces()
2020

2121
spaces = config.workflow.spaces

fmriprep/workflows/tests.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def mock_config():
2121
if sectionname != 'environment':
2222
section = getattr(config, sectionname)
2323
section.load(configs)
24-
config.set_logger_level()
24+
config.init_loggers()
2525
config.init_spaces()
2626

2727
config.execution.work_dir = Path(mkdtemp())

0 commit comments

Comments
 (0)