# -*- coding: utf-8 -*-
'''
SPM configuration module
Classes
=======
:class:`SPMConfig`
------------------
'''
from __future__ import absolute_import
from traits.api import Directory, File, Bool, Enum, Undefined, Str
from capsul.study_config.study_config import StudyConfigModule
from capsul.subprocess.spm import check_spm_configuration
from capsul.engine import CapsulEngine
import glob
import os
import os.path as osp
[docs]
class SPMConfig(StudyConfigModule):
""" SPM configuration.
There is two ways to configure SPM:
* the first one requires to configure matlab and then to set the spm
directory.
* the second one is based on a standalone version of spm and requires
to set the spm executable directory.
"""
dependencies = ["MatlabConfig"]
def __init__(self, study_config, configuration):
super(SPMConfig, self).__init__(study_config, configuration)
self.study_config.add_trait("spm_directory", Directory(
Undefined,
output=False,
desc="Directory containing SPM.",
groups=['spm']))
self.study_config.add_trait("spm_standalone", Bool(
Undefined,
desc="If True, use the standalone version of SPM.",
groups=['spm']))
self.study_config.add_trait('spm_version', Str(
Undefined, output=False,
desc='Version string for SPM: "12", "8", etc.',
groups=['spm']))
self.study_config.add_trait("spm_exec", File(
Undefined,
output=False,
desc="SPM standalone (MCR) command path (run_spm12.sh file).",
groups=['spm']))
self.study_config.add_trait(
'spm_mcr_directory',
Directory(Undefined, output=False,
desc='Matlab MCR directory for standalone version',
groups=['spm']))
self.study_config.add_trait("use_spm", Bool(
Undefined,
desc="If True, SPM configuration is checked on module "
"initialization.",
groups=['spm']))
[docs]
def initialize_module(self):
if 'capsul.engine.module.spm' \
not in self.study_config.engine._loaded_modules:
self.study_config.engine.load_module('capsul.engine.module.spm')
if type(self.study_config.engine) is not CapsulEngine:
# engine is a proxy, thus we are initialized from a real
# CapsulEngine, which holds the reference values
self.sync_from_engine()
else:
self.sync_to_engine()
# this test aims to raise an exception in case of incorrect setting,
# complying to capsul 2.x behavior.
if self.study_config.use_spm is True:
check_spm_configuration(self.study_config)
[docs]
def initialize_callbacks(self):
self.study_config.on_trait_change(self.sync_to_engine,
"[use_spm, spm_+]")
# WARNING ref to self in callback
self.study_config.engine.settings.module_notifiers[
'capsul.engine.module.spm'] = [self.sync_from_engine]
def sync_from_engine(self, param=None, value=None):
if getattr(self, '_syncing', False):
# manage recursive calls
return
self._syncing = True
try:
if 'SPMConfig' in self.study_config.modules \
and 'capsul.engine.module.spm' \
in self.study_config.engine._loaded_modules:
with self.study_config.engine.settings as session:
configs = list(session.configs('spm', 'global'))
configs = sorted(
configs,
key=lambda x: (
-int(x.version)
if x.version not in ('', None)
else 0)
* 1000 - int(bool(x.standalone)))
mlconfigs = list(session.configs('matlab', 'global'))
mlconfig = None
if len(mlconfigs) != 0:
mlconfig = mlconfigs[0]
if len(configs) != 0:
config = configs[0]
directory = config.directory \
if config.directory not in (None, '') \
else Undefined
self.study_config.spm_directory = directory
if mlconfig and mlconfig.mcr_directory:
self.study_config.spm_mcr_directory \
= mlconfig.mcr_directory
self.study_config.spm_standalone \
= bool(config.standalone)
if config.version is not None:
self.study_config.spm_version = config.version
else:
self.study_config.spm_version = '0'
if directory not in (None, Undefined):
if config.version:
spm_exec = \
osp.join(directory,
'run_spm%s.sh' % config.version)
if os.path.exists(spm_exec):
spm_exec = [spm_exec]
else:
spm_exec = []
else:
spm_exec = glob.glob(osp.join(
directory,
'run_spm*.sh'))
if len(spm_exec) != 0:
self.study_config.spm_exec = spm_exec[0]
else:
self.study_config.spm_exec = Undefined
if self.study_config.spm_directory \
not in (None, Undefined) \
and self.study_config.spm_exec \
not in (None, Undefined) \
and (not self.study_config.spm_standalone
or self.study_config.spm_mcr_directory
not in (None, Undefined)):
self.study_config.use_spm = True
else:
self.study_config.use_spm = False
finally:
del self._syncing
def sync_to_engine(self):
if getattr(self, '_syncing', False):
# manage recursive calls
return
self._syncing = True
try:
if 'SPMConfig' in self.study_config.modules \
and 'capsul.engine.module.spm' \
in self.study_config.engine._loaded_modules:
with self.study_config.engine.settings as session:
cif = self.study_config.engine.settings.config_id_field
version = self.study_config.spm_version
if version in (None, Undefined):
version = '12'
standalone = (self.study_config.spm_standalone is True)
id = 'spm%s%s' % (version,
'-standalone' if standalone else '')
query = '%s == "%s"' % (cif, id)
config = session.config('spm', 'global', selection=query)
if config is None:
# FIXME: do we keep only one config ? yes for now.
config_ids = [getattr(conf, cif)
for conf in session.configs('spm',
'global')
if getattr(conf, cif) != id]
for config_id in config_ids:
session.remove_config('spm', 'global', config_id)
sconf = {
'directory':
self.study_config.spm_directory
if self.study_config.spm_directory
is not Undefined
else None,
'version': version,
'standalone': standalone,
cif: id}
session.new_config('spm', 'global', sconf)
else:
tparam = {'spm_directory': 'directory',
'spm_standalone': 'standalone',
'spm_version': 'version'}
params = ['spm_directory',
'spm_standalone',
'spm_version']
defaults = {'directory': None, 'standalone': False,
'version': '12'}
for p in params:
val = getattr(self.study_config, p)
ceparam = tparam[p]
if val is Undefined:
val = defaults.get(ceparam, None)
setattr(config, ceparam, val)
val = self.study_config.spm_exec
if val is Undefined:
val = None
else:
val = osp.dirname(self.study_config.spm_exec)
config.directory = val
if self.study_config.spm_mcr_directory \
and self.study_config.spm_standalone:
config = session.config('matlab', 'global',
selection='%s == "matlab"'
% cif)
mcr_dir = self.study_config.spm_mcr_directory
if mcr_dir is Undefined:
mcr_dir = None
if config is None:
session.new_config(
'matlab', 'global',
{'mcr_directory': mcr_dir,
'config_id': 'matlab'})
else:
config.mcr_directory = mcr_dir
finally:
del self._syncing