Skip to content

Commit

Permalink
Merge pull request #1245 from nipreps/fix/update-inputs-1244
Browse files Browse the repository at this point in the history
FIX: Revise config save/load and update inputs after dropping
  • Loading branch information
oesteban committed Apr 10, 2024
2 parents 9b5c2f6 + 5950b7f commit fb99dbd
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 36 deletions.
2 changes: 1 addition & 1 deletion mriqc/cli/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,7 @@ def parse_args(args=None, namespace=None):
))
config.loggers.default.addHandler(_handler)

extra_messages = []
extra_messages = ['']

if opts.bids_filter_file:
extra_messages.insert(
Expand Down
15 changes: 5 additions & 10 deletions mriqc/cli/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,9 @@ def main():
# straightforward way to communicate with the child process is via the filesystem.
# The config file name needs to be unique, otherwise multiple mriqc instances
# will create write conflicts.
config_file = mkstemp(
dir=config.execution.work_dir, prefix='.mriqc.', suffix='.toml'
)[1]

config.to_filename(config_file)
config.loggers.cli.info(
f'Saved MRIQC config file: {config_file}.')
config.file_path = config_file
config_file = config.to_filename()
config.loggers.cli.info(f'MRIQC config file: {config_file}.')

exitcode = 0
# Set up participant level
if 'participant' in config.workflow.analysis_level:
Expand All @@ -81,7 +76,7 @@ def main():
_pool = ProcessPoolExecutor(
max_workers=config.nipype.nprocs,
initializer=config._process_initializer,
initargs=(config.file_path,),
initargs=(config_file,),
)

_resmon = None
Expand Down Expand Up @@ -153,7 +148,7 @@ def main():
if mriqc_wf and config.execution.write_graph:
mriqc_wf.write_graph(graph2use='colored', format='svg', simple_form=True)

if not config.execution.dry_run or not config.execution.reports_only:
if not config.execution.dry_run and not config.execution.reports_only:
# Warn about submitting measures BEFORE
if not config.execution.no_sub:
config.loggers.cli.warning(config.DSA_MESSAGE)
Expand Down
74 changes: 50 additions & 24 deletions mriqc/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
import sys
from contextlib import suppress
from pathlib import Path
from tempfile import mkstemp
from time import strftime
from uuid import uuid4

Expand Down Expand Up @@ -205,12 +206,6 @@
_memory_gb = float(_mem_str) / (1024.0**3)


file_path: Path = None
"""
Path to configuration file.
"""


class _Config:
"""An abstract class forbidding instantiation."""

Expand All @@ -221,9 +216,9 @@ def __init__(self):
raise RuntimeError('Configuration type is not instantiable.')

@classmethod
def load(cls, settings, init=True):
def load(cls, sections, init=True):
"""Store settings from a dictionary."""
for k, v in settings.items():
for k, v in sections.items():
if v is None:
continue
if k in cls._paths:
Expand Down Expand Up @@ -253,6 +248,15 @@ def get(cls):
return out


class settings(_Config):
"""Settings of this config module."""

file_path: Path = None
"""Path to this configuration file."""

_paths = ('file_path', )


class environment(_Config):
"""
Read-only options regarding the platform and environment.
Expand Down Expand Up @@ -545,8 +549,11 @@ class workflow(_Config):
"""Turn on FFT based spike detector (slow)."""
inputs = None
"""List of files to be processed with MRIQC."""
min_len_dwi = 5
"""Minimum DWI length to be considered a "processable" dataset."""
min_len_dwi = 7
"""
Minimum DWI length to be considered a "processable" dataset
(default: 7, assuming one low-b and six gradients for diffusion tensor imaging).
"""
species = 'human'
"""Subject species to choose most appropriate template"""
template_id = 'MNI152NLin2009cAsym'
Expand All @@ -561,7 +568,7 @@ class loggers:

default = logging.getLogger()
"""The root logger."""
cli = logging.getLogger('cli')
cli = logging.getLogger('mriqc')
"""Command-line interface logging."""
workflow = None
"""NiPype's workflow logger."""
Expand Down Expand Up @@ -618,39 +625,45 @@ def getLogger(cls, name):
return retval


def from_dict(settings):
def from_dict(sections):
"""Read settings from a flat dictionary."""
execution.load(settings)
workflow.load(settings)
nipype.load(settings, init=False)
execution.load(sections)
workflow.load(sections)
nipype.load(sections, init=False)


def load(filename):
"""Load settings from file."""
from toml import loads

filename = Path(filename)
settings = loads(filename.read_text())
for sectionname, configs in settings.items():
sections = loads(filename.read_text())
for sectionname, configs in sections.items():
if sectionname != 'environment':
section = getattr(sys.modules[__name__], sectionname)
section.load(configs)

if settings.file_path is None:
settings.file_path = filename

loggers.cli.debug(f'Loaded MRIQC config file: {settings.file_path}.')


def get(flat=False):
"""Get config as a dict."""
settings = {
sections = {
'environment': environment.get(),
'execution': execution.get(),
'workflow': workflow.get(),
'nipype': nipype.get(),
'settings': settings.get(),
}
if not flat:
return settings
return sections

return {
'.'.join((section, k)): v
for section, configs in settings.items()
for section, configs in sections.items()
for k, v in configs.items()
}

Expand All @@ -662,11 +675,24 @@ def dumps():
return dumps(get())


def to_filename(filename):
def to_filename(filename=None):
"""Write settings to file."""
filename = Path(filename)
filename.parent.mkdir(exist_ok=True, parents=True)
filename.write_text(dumps())

if filename:
settings.file_path = Path(filename)
elif settings.file_path is None:
settings.file_path = Path(
mkstemp(
dir=execution.work_dir,
prefix='.mriqc.',
suffix='.toml'
)[1],
)

settings.file_path.parent.mkdir(exist_ok=True, parents=True)
settings.file_path.write_text(dumps())
loggers.cli.debug(f'Saved MRIQC config file: {settings.file_path}.')
return settings.file_path


def _process_initializer(config_file: Path):
Expand Down
2 changes: 1 addition & 1 deletion mriqc/engine/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -447,7 +447,7 @@ def __init__(self, pool=None, plugin_args=None):
self.pool = pool or ProcessPoolExecutor(
max_workers=self.processors,
initializer=config._process_initializer,
initargs=(config.file_path,),
initargs=(config.settings.file_path,),
mp_context=mp_context,
)

Expand Down
4 changes: 4 additions & 0 deletions mriqc/workflows/diffusion/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,10 @@ def dmri_qc_workflow(name='dwiMRIQC'):
'insufficient in number to execute the workflow.'
)

if set(dataset) - set(full_data):
config.workflow.inputs['dwi'] = full_data
config.to_filename()

message = BUILDING_WORKFLOW.format(
modality='diffusion',
detail=(
Expand Down

0 comments on commit fb99dbd

Please sign in to comment.