# -*- coding: utf-8 -*-
'''
Specific subprocess-like functions to call FSL taking into account a
potential configuration done in StudyConfig. If a StudyConfig is not
configured to use FSL, it may be automatically configured. Automatic
configuration had been tested in the two following cases:
- FSL was installed from the FMRIB site and, at least, FSLDIR
environment variable is set (fsl.sh can be sourced or not)
- FSL was installed from Neurodebian packages
For calling FSL command with this module, the first arguent of
command line must be the FSL executable without any path nor prefix.
Prefix areused in Neurodebian install. For instance on Ubuntu 16.04
Neurodebian FSL commands are prefixed with "fsl5.0-".
The appropriate path and eventually prefix are added from the configuration
of the StudyConfig instance.
Classes
=======
:class:`Popen`
--------------
Functions
=========
:func:`fsl_command_with_environment`
------------------------------------
:func:`check_fsl_configuration`
-------------------------------
:func:`check_configuration_values`
----------------------------------
:func:`auto_configuration`
--------------------------
:func:`call`
------------
:func:`check_call`
------------------
:func:`check_output`
--------------------
'''
from __future__ import absolute_import
import os
import os.path as osp
import soma.subprocess
from traits.api import Undefined
from soma.path import find_in_path
from capsul.engine.module import fsl as fsl_engine
[docs]def fsl_command_with_environment(study_config, command):
'''
Given an FSL command where first element is a command name without
any path or prefix (e.g. "bet"). Returns the appropriate command to
call taking into account the study_config FSL configuration.
'''
fsl_dir = os.environ.get('FSLDIR')
if fsl_dir:
dir_prefix = '%s/bin/' % fsl_dir
else:
dir_prefix = ''
fsl_prefix = getattr(study_config, 'fsl_prefix', '')
if fsl_prefix is Undefined:
fsl_prefix = ''
if getattr(study_config, 'fsl_config', Undefined) is Undefined:
cmd = ['%s%s%s' % (dir_prefix,
fsl_prefix,
command[0])] + command[1:]
else:
fsldir = osp.dirname(osp.dirname(osp.dirname(study_config.fsl_config)))
shell = os.environ.get('SHELL', '/bin/sh')
if shell.endswith('csh'):
cmd = [shell, '-c',
'setenv FSLDIR "{0}";source {0}/etc/fslconf/fsl.csh;exec {0}/bin/{1}{2} '.format(fsldir, fsl_prefix, command[0]) + \
' '.join("'%s'" % i.replace("'", "\\'") for i in command[1:])]
else:
cmd = [shell, '-c',
'export FSLDIR="{0}";. {0}/etc/fslconf/fsl.sh;exec {0}/bin/{1}{2} '.format(fsldir, fsl_prefix, command[0]) + \
' '.join("'%s'" % i.replace("'", "\\'") for i in command[1:])]
return cmd
[docs]def check_fsl_configuration(study_config):
'''
Check thas study_config configuration is valid to call FSL commands.
If not, try to automatically configure FSL. Finally raises an
EnvironmentError if configuration is still wrong.
'''
if getattr(study_config, '_fsl_config_checked', False):
# Check FLS configuration only once
return
if 'FSLConfig' not in study_config.modules:
raise EnvironmentError('FSLConfig module is missing in StudyConfig.')
if study_config.use_fsl is False:
raise EnvironmentError('Configuration is set not to use FLS. Set use_fsl to True in order to use FSL.')
# Configuration must be valid otherwise
# try to update configuration and recheck is validity
if check_configuration_values(study_config) is not None:
auto_configuration(study_config)
error_message = check_configuration_values(study_config)
if error_message:
raise EnvironmentError(error_message)
study_config.use_fsl = True
study_config._fsl_config_checked = True
[docs]def check_configuration_values(study_config):
'''
Check if the configuration is valid to run FLS and returns an error
message if there is an error or None if everything is good.
'''
fsl_prefix = getattr(study_config, 'fsl_prefix', '')
if fsl_prefix is Undefined:
fsl_prefix = ''
if study_config.fsl_config is Undefined:
if not find_in_path('%sbet' % fsl_prefix):
return 'FSL command "%sbet" cannot be found in PATH' % fsl_prefix
else:
if fsl_prefix:
return 'FSL configuration must either use fsl_config or fsl_prefix but not both'
if not osp.exists(study_config.fsl_config):
return 'File "%s" does not exist' % study_config.fsl_config
if not study_config.fsl_config.endswith('fsl.sh'):
return 'File "%s" is not a path to fsl.sh script' % study_config.fsl_config
return None
[docs]def auto_configuration(study_config):
'''
Try to automatically set the study_config configuration for FSL.
'''
fsl_dir = os.environ.get('FSLDIR')
fsl_prefix = getattr(study_config, 'fsl_prefix', '')
if fsl_prefix is Undefined:
fsl_prefix = ''
if fsl_dir and not fsl_prefix:
# Try to set fsl_config from FSLDIR environment variable
fsl_config = '%s/etc/fslconf/fsl.sh' % fsl_dir
if osp.exists(fsl_config):
study_config.fsl_config = fsl_config
elif not fsl_prefix:
# Try to set fsl_prefix by searching fsl-*bet in PATH
bet = find_in_path('fsl*-bet')
if bet:
study_config.fsl_prefix = osp.basename(bet)[:-3]
[docs]class Popen(soma.subprocess.Popen):
'''
Equivalent to Python subprocess.Popen for FSL commands
'''
def __init__(self, study_config, command, **kwargs):
check_fsl_configuration(study_config)
cmd = fsl_command_with_environment(study_config, command)
super(Popen, self).__init__(cmd, **kwargs)
[docs]def call(study_config, command, **kwargs):
'''
Equivalent to Python subprocess.call for FSL commands
'''
check_fsl_configuration(study_config)
cmd = fsl_command_with_environment(study_config, command)
return soma.subprocess.call(cmd, **kwargs)
[docs]def check_call(study_config, command, **kwargs):
'''
Equivalent to Python subprocess.check_call for FSL commands
'''
check_fsl_configuration(study_config)
cmd = fsl_command_with_environment(study_config, command)
return soma.subprocess.check_call(cmd, **kwargs)
[docs]def check_output(study_config, command, **kwargs):
'''
Equivalent to Python subprocess.check_output for FSL commands
'''
check_fsl_configuration(study_config)
cmd = fsl_command_with_environment(study_config, command)
return soma.subprocess.check_output(cmd, **kwargs)