diff --git a/capsul/config/afni.py b/capsul/config/afni.py index 9bdb38e96..56dbfc995 100644 --- a/capsul/config/afni.py +++ b/capsul/config/afni.py @@ -1,5 +1,5 @@ from .configuration import ModuleConfiguration -from soma.controller import Directory, undefined, File, field +from soma.controller import Directory, undefined, field class AfniConfiguration(ModuleConfiguration): @@ -15,11 +15,11 @@ def is_valid_config(self, requirements): return False return True + @staticmethod + def init_execution_context(execution_context): + """ + Configure execution (env variables) from a configured execution context + """ + from capsul.in_context import afni -def init_execution_context(execution_context): - """ - Configure an execution context given a capsul_engine and some requirements. - """ - config = execution_context.config["modules"]["afni"] - execution_context.afni = AfniConfiguration() - execution_context.afni.import_from_dict(config) + afni.set_env_from_config(execution_context) diff --git a/capsul/config/ants.py b/capsul/config/ants.py index 2fe2c8dab..eb05d121b 100644 --- a/capsul/config/ants.py +++ b/capsul/config/ants.py @@ -1,5 +1,5 @@ from .configuration import ModuleConfiguration -from soma.controller import Directory, undefined, File, field +from soma.controller import Directory, undefined, field class AntsConfiguration(ModuleConfiguration): @@ -15,11 +15,11 @@ def is_valid_config(self, requirements): return False return True + @staticmethod + def init_execution_context(execution_context): + """ + Configure execution (env variables) from a configured execution context + """ + from capsul.in_context import ants -def init_execution_context(execution_context): - """ - Configure an execution context given a capsul_engine and some requirements. - """ - config = execution_context.config["modules"]["ants"] - execution_context.ants = AntsConfiguration() - execution_context.ants.import_from_dict(config) + ants.set_env_from_config(execution_context) diff --git a/capsul/config/axon.py b/capsul/config/axon.py index 2bcf76667..fbfb4d4cb 100644 --- a/capsul/config/axon.py +++ b/capsul/config/axon.py @@ -50,12 +50,3 @@ def axon_default_shared_dir(): @staticmethod def axon_default_version(): return axon_default_version() - - -def init_execution_context(execution_context): - """ - Configure an execution context given a capsul_engine and some requirements. - """ - config = execution_context.config["modules"]["axon"] - execution_context.axon = AxonConfiguration() - execution_context.axon.import_from_dict(config) diff --git a/capsul/config/configuration.py b/capsul/config/configuration.py index a8d5b1a4d..a6be70889 100644 --- a/capsul/config/configuration.py +++ b/capsul/config/configuration.py @@ -191,6 +191,9 @@ def add_module(self, module_name, allow_existing=False): doc=cls.__doc__, default_factory=OpenKeyDictController[cls], ) + if self.config_modules is undefined: + self.config_modules = [] + self.config_modules.append(module_name) if hasattr(cls, "module_dependencies"): module_dependencies = getattr(cls, "module_dependencies") diff --git a/capsul/config/freesurfer.py b/capsul/config/freesurfer.py index e7464bc21..e7f460f91 100644 --- a/capsul/config/freesurfer.py +++ b/capsul/config/freesurfer.py @@ -16,11 +16,11 @@ def is_valid_config(self, requirements): return False return True + @staticmethod + def init_execution_context(execution_context): + """ + Configure execution (env variables) from a configured execution context + """ + from capsul.in_context import freesurfer -def init_execution_context(execution_context): - """ - Configure an execution context given a capsul_engine and some requirements. - """ - config = execution_context.config["modules"]["freesurfer"] - execution_context.freesurfer = FreesurferConfiguration() - execution_context.freesurfer.import_from_dict(config) + freesurfer.set_env_from_config(execution_context) diff --git a/capsul/config/fsl.py b/capsul/config/fsl.py index b32474cf5..186a26c4a 100644 --- a/capsul/config/fsl.py +++ b/capsul/config/fsl.py @@ -17,11 +17,11 @@ def is_valid_config(self, requirements): return False return True + @staticmethod + def init_execution_context(execution_context): + """ + Configure execution (env variables) from a configured execution context + """ + from capsul.in_context import fsl -def init_execution_context(execution_context): - """ - Configure an execution context given a capsul_engine and some requirements. - """ - config = execution_context.config["modules"]["fsl"] - execution_context.fsl = FSLConfiguration() - execution_context.fsl.import_from_dict(config) + fsl.set_env_from_config(execution_context) diff --git a/capsul/config/matlab.py b/capsul/config/matlab.py index acddbb2b3..004317d19 100644 --- a/capsul/config/matlab.py +++ b/capsul/config/matlab.py @@ -50,11 +50,11 @@ def is_valid_config(self, requirements): return False return True - -def init_execution_context(execution_context): - """ - Configure an execution context given a capsul_engine and some requirements. - """ - config = execution_context.config["modules"]["matlab"] - execution_context.matlab = MatlabConfiguration() - execution_context.matlab.import_dict(config) + @staticmethod + def init_execution_context(execution_context): + """ + Configure execution (env variables) from a configured execution context + """ + from capsul.in_context import matlab + + matlab.set_env_from_config(execution_context) diff --git a/capsul/config/mrtrix.py b/capsul/config/mrtrix.py new file mode 100644 index 000000000..041ef3261 --- /dev/null +++ b/capsul/config/mrtrix.py @@ -0,0 +1,25 @@ +from .configuration import ModuleConfiguration +from soma.controller import Directory, undefined, field + + +class MRTrixConfiguration(ModuleConfiguration): + """MRTrix configuration module""" + + version: str + directory: Directory = field(optional=True) + name = "mrtrix" + + def is_valid_config(self, requirements): + required_version = requirements.get("version") + if required_version and getattr(self, "version", undefined) != required_version: + return False + return True + + @staticmethod + def init_execution_context(execution_context): + """ + Configure execution (env variables) from a configured execution context + """ + from capsul.in_context import mrtrix + + mrtrix.set_env_from_config(execution_context) diff --git a/capsul/config/nipype.py b/capsul/config/nipype.py index 971adc210..ef29acfd9 100644 --- a/capsul/config/nipype.py +++ b/capsul/config/nipype.py @@ -154,7 +154,7 @@ def configure_freesurfer(context): freesurfer.FSCommand.set_default_subjects_dir(subjects_dir) from capsul.in_context import freesurfer as fsrun - env = fsrun.freesurfer_env() + env = fsrun.freesurfer_env(execution_context=context) for var, value in env.items(): os.environ[var] = value diff --git a/capsul/config/python.py b/capsul/config/python.py index ee518c4fb..2b5de5be1 100644 --- a/capsul/config/python.py +++ b/capsul/config/python.py @@ -16,12 +16,3 @@ def is_valid_config(self, requirements): if required_version and getattr(self, "version", undefined) != required_version: return False return True - - -def init_execution_context(execution_context): - """ - Configure an execution context given a capsul_engine and some requirements. - """ - config = execution_context.config["modules"]["python"] - execution_context.python = PythonConfiguration() - execution_context.python.import_from_dict(config) diff --git a/capsul/config/spm.py b/capsul/config/spm.py index f7e75af6c..76296af7a 100644 --- a/capsul/config/spm.py +++ b/capsul/config/spm.py @@ -21,11 +21,11 @@ def is_valid_config(self, requirements): else: return {"matlab": {"mcr": False}} + @staticmethod + def init_execution_context(execution_context): + """ + Configure execution (env variables) from a configured execution context + """ + from capsul.in_context import spm -def init_execution_context(execution_context): - """ - Configure an execution context given a capsul_engine and some requirements. - """ - config = execution_context.config["modules"]["spm"] - execution_context.spm = SPMConfiguration() - execution_context.spm.import_dict(config) + spm.set_env_from_config(execution_context) diff --git a/capsul/engine/__init__.py b/capsul/engine/__init__.py index ddf7149f6..3afa93cc3 100644 --- a/capsul/engine/__init__.py +++ b/capsul/engine/__init__.py @@ -27,7 +27,9 @@ def execution_context(engine_label, engine_config, executable): for conf_item in ("dataset", "config_modules", "python_modules"): if conf_item in cdict: config[conf_item] = cdict[conf_item] - execution_context = ExecutionContext(executable=executable, config=config) + execution_context = ExecutionContext( + executable=executable, config=config, activate_modules=False + ) req_to_check = execution_context.executable_requirements(executable) done_req = [] # record requirements to avoid loops @@ -60,7 +62,7 @@ def execution_context(engine_label, engine_config, executable): # now check we have only one module for each for module_name in needed_modules: valid_module_configs = valid_configs.get(module_name) - if not valid_module_configs: + if valid_module_configs is None: raise RuntimeError( f'Execution environment "{engine_label}" has no ' f"valid configuration for module {module_name}" @@ -81,6 +83,10 @@ def execution_context(engine_label, engine_config, executable): module_name, type_=ModuleConfiguration, override=True ) setattr(execution_context, module_name, valid_config) + + # FIXME: should be done only in real execution (server) situation + execution_context.activate_modules_config() + return execution_context diff --git a/capsul/execution_context.py b/capsul/execution_context.py index a65a8d1f9..c8c3e46bc 100644 --- a/capsul/execution_context.py +++ b/capsul/execution_context.py @@ -25,17 +25,17 @@ class ExecutionContext(Controller): config_modules: list[str] dataset: OpenKeyDictController[Dataset] - def __init__(self, config=None, executable=None): - mod_classes = [] + def __init__(self, config=None, executable=None, activate_modules=True): + super().__init__() if config: python_modules = config.get("python_modules", ()) for m in python_modules: importlib.import_module(m) config_modules = config.get("config_modules", ()) + self.config_modules = config_modules for m in config_modules: # The following function loads the appropriate module get_config_class(m) - super().__init__() self.dataset = OpenKeyDictController[Dataset]() if config is not None: for k in list(config.keys()): @@ -53,14 +53,17 @@ def __init__(self, config=None, executable=None): k = new_k if cls: self.add_field(k, cls, doc=cls.__doc__, default_factory=cls) - mod_classes.append(cls) dataset = config.pop("dataset", None) if dataset: self.dataset = dataset self.import_dict(config) self.executable = executable + if activate_modules: + self.activate_modules_config() - for cls in mod_classes: + def activate_modules_config(self): + for cm in self.config_modules: + cls = get_config_class(cm) if hasattr(cls, "init_execution_context"): cls.init_execution_context(self) diff --git a/capsul/in_context/__init__.py b/capsul/in_context/__init__.py index e4c10ddef..bfff6e8e1 100644 --- a/capsul/in_context/__init__.py +++ b/capsul/in_context/__init__.py @@ -1,15 +1,19 @@ # -*- coding: utf-8 -*- """ -The ``in_context`` module provides functions to call some external software from Capsul processes (SPM, FSL, etc.). The main functions perform calls to the software in a similar way as ``subprocess`` functions (:class:`~subprocess.Popen`, :func:`~subprocess.call`, :func:`~subprocess.check_call` and :func:`subprocess.check_output`). These functions are only valid when the software environment *context* is activated. -Activating the context is normally done using the ``with`` statement on a :class:`~capsul.engine.CapsulEngine` object:: +The ``in_context`` module provides functions to call some external software from Capsul processes (SPM, FSL, etc.). The main functions perform calls to the software in a similar way as ``subprocess`` functions (:class:`~subprocess.Popen`, :func:`~subprocess.call`, :func:`~subprocess.check_call` and :func:`subprocess.check_output`). +The notable difference is that they use an :class:`~capsul.execution_context.ExecutionContext` object instance to get configuration from. +These functions are only run from within the :meth:`~capsul.process.Process.execute` method of a Process, which gets the context as a paremeter:: - from capsul.engine import capsul_engine + from capsul.api import Process from capsul.in_context.fsl import fsl_check_call - ce = capsul_engine() + ce = Capsul() # .. configure it ... + Class MyProcess(Process): - with ce: - fsl_check_call(['bet', '-h']) + # [declare fields etc] ... + + def execute(self, execution_context): + fsl_check_call(['bet', '-h'], execution_context=execution_context) """ diff --git a/capsul/in_context/afni.py b/capsul/in_context/afni.py index cad1877f3..076b51b22 100644 --- a/capsul/in_context/afni.py +++ b/capsul/in_context/afni.py @@ -1,16 +1,15 @@ # -*- coding: utf-8 -*- """ Specific subprocess-like functions to call AFNI taking into account -configuration stored in ExecutionContext. To functions and class in -this module it is mandatory to activate an ExecutionContext (using a -with statement). For instance:: +configuration stored in ExecutionContext.For instance:: - from capsul.engine import capsul_engine - from capsul.in_context.afni import afni_check_call + from capsul.engine import Capsul + from capsul.in_context.afni import afni_check_call - ce = capsul_engine() - with ce: - afni_check_call(['bet', '/somewhere/myimage.nii']) + c = Capsul(user_file='my_config.json') + p = c.executable('nipype.interfaces.afni.preprocess.Automask') + ce = c.engine().execution_context(p) + afni_check_call(['afni_comamnd', '/somewhere/myimage.nii']) For calling AFNI command with this module, the first argument of command line must be the AFNI executable without any path. @@ -18,18 +17,30 @@ of the ExecutionContext. """ -from __future__ import absolute_import - import os import os.path as osp -import soma.subprocess +import subprocess from soma.utils.env import parse_env_lines -import six +from soma.controller import undefined + afni_runtime_env = None -def afni_command_with_environment(command, use_runtime_env=True): +def set_env_from_config(execution_context): + """ + Set environment variables FSLDIR, FSL_CONFIG, FSL_PREFIX according to the + execution context configuration. + """ + afni_mod = getattr(execution_context, "afni") + if afni_mod: + if afni_mod.directory is not undefined: + os.environ["AFNIPATH"] = afni_mod.directory + + +def afni_command_with_environment( + command, execution_context=None, use_runtime_env=True +): """ Given an AFNI command where first element is a command name without any path. Returns the appropriate command to call taking into account @@ -37,6 +48,9 @@ def afni_command_with_environment(command, use_runtime_env=True): activated ExecutionContext. """ + if execution_context is not None: + set_env_from_config(execution_context) + if use_runtime_env and afni_runtime_env: c0 = list(osp.split(command[0])) c0 = osp.join(*c0) @@ -44,6 +58,7 @@ def afni_command_with_environment(command, use_runtime_env=True): return cmd afni_dir = os.environ.get("AFNIPATH") + cmd = command if afni_dir: shell = os.environ.get("SHELL", "/bin/sh") if shell.endswith("csh"): @@ -68,7 +83,7 @@ def afni_command_with_environment(command, use_runtime_env=True): return cmd -def afni_env(): +def afni_env(execution_context=None): """ get AFNI env variables process @@ -78,17 +93,18 @@ def afni_env(): if afni_runtime_env is not None: return afni_runtime_env + if execution_context is not None: + set_env_from_config(execution_context) + afni_dir = os.environ.get("AFNIPATH") kwargs = {} cmd = afni_command_with_environment(["env"], use_runtime_env=False) - new_env = soma.subprocess.check_output(cmd, **kwargs).decode("utf-8").strip() + new_env = subprocess.check_output(cmd, **kwargs).decode("utf-8").strip() new_env = parse_env_lines(new_env) env = {} - for l in new_env: - name, val = l.strip().split("=", 1) - name = six.ensure_str(name) - val = six.ensure_str(val) + for line in new_env: + name, val = line.strip().split("=", 1) if name not in ("_", "SHLVL") and ( name not in os.environ or os.environ[name] != val ): @@ -102,35 +118,37 @@ def afni_env(): return env -class AFNIPopen(soma.subprocess.Popen): +class AFNIPopen(subprocess.Popen): """ Equivalent to Python subprocess.Popen for AFNI commands """ - def __init__(self, command, **kwargs): - cmd = afni_command_with_environment(command) + def __init__(self, command, execution_context=None, **kwargs): + cmd = afni_command_with_environment( + command, execution_context=execution_context + ) super(AFNIPopen, self).__init__(cmd, **kwargs) -def afni_call(command, **kwargs): +def afni_call(command, execution_context=None, **kwargs): """ Equivalent to Python subprocess.call for AFNI commands """ - cmd = afni_command_with_environment(command) - return soma.subprocess.call(cmd, **kwargs) + cmd = afni_command_with_environment(command, execution_context=execution_context) + return subprocess.call(cmd, **kwargs) -def afni_check_call(command, **kwargs): +def afni_check_call(command, execution_context=None, **kwargs): """ Equivalent to Python subprocess.check_call for AFNI commands """ - cmd = afni_command_with_environment(command) - return soma.subprocess.check_call(cmd, **kwargs) + cmd = afni_command_with_environment(command, execution_context=execution_context) + return subprocess.check_call(cmd, **kwargs) -def afni_check_output(command, **kwargs): +def afni_check_output(command, execution_context=None, **kwargs): """ Equivalent to Python subprocess.check_output for AFNI commands """ - cmd = afni_command_with_environment(command) - return soma.subprocess.check_output(cmd, **kwargs) + cmd = afni_command_with_environment(command, execution_context=execution_context) + return subprocess.check_output(cmd, **kwargs) diff --git a/capsul/in_context/ants.py b/capsul/in_context/ants.py index c50438911..0b3078e42 100644 --- a/capsul/in_context/ants.py +++ b/capsul/in_context/ants.py @@ -1,16 +1,15 @@ # -*- coding: utf-8 -*- """ Specific subprocess-like functions to call ANTS taking into account -configuration stored in ExecutionContext. To functions and class in -this module it is mandatory to activate an ExecutionContext (using a -with statement). For instance:: +configuration stored in ExecutionContext.For instance:: - from capsul.engine import capsul_engine - from capsul.in_context.ants import ants_check_call + from capsul.engine import Capsul + from capsul.in_context.afni import ants_check_call - ce = capsul_engine() - with ce: - ants_check_call(['bet', '/somewhere/myimage.nii']) + c = Capsul(user_file='my_config.json') + p = c.executable('nipype.interfaces.afni.preprocess.Automask') + ce = c.engine().execution_context(p) + ants_check_call(['ants_comamnd', '/somewhere/myimage.nii']) For calling ANTS command with this module, the first argument of command line must be the ANTS executable without any path. @@ -18,18 +17,30 @@ of the ExecutionContext. """ -from __future__ import absolute_import - import os import os.path as osp -import soma.subprocess +import subprocess from soma.utils.env import parse_env_lines -import six +from soma.controller import undefined + ants_runtime_env = None -def ants_command_with_environment(command, use_runtime_env=True): +def set_env_from_config(execution_context): + """ + Set environment variables FSLDIR, FSL_CONFIG, FSL_PREFIX according to the + execution context configuration. + """ + ants_mod = getattr(execution_context, "ants") + if ants_mod: + if ants_mod.directory is not undefined: + os.environ["ANTSPATH"] = ants_mod.directory + + +def ants_command_with_environment( + command, execution_context=None, use_runtime_env=True +): """ Given an ANTS command where first element is a command name without any path. Returns the appropriate command to call taking into account @@ -37,6 +48,9 @@ def ants_command_with_environment(command, use_runtime_env=True): activated ExecutionContext. """ + if execution_context is not None: + set_env_from_config(execution_context) + if use_runtime_env and ants_runtime_env: c0 = list(osp.split(command[0])) c0 = osp.join(*c0) @@ -44,6 +58,7 @@ def ants_command_with_environment(command, use_runtime_env=True): return cmd ants_dir = os.environ.get("ANTSPATH") + cmd = command if ants_dir: shell = os.environ.get("SHELL", "/bin/sh") if shell.endswith("csh"): @@ -68,7 +83,7 @@ def ants_command_with_environment(command, use_runtime_env=True): return cmd -def ants_env(): +def ants_env(execution_context=None): """ get ANTS env variables process @@ -78,17 +93,18 @@ def ants_env(): if ants_runtime_env is not None: return ants_runtime_env + if execution_context is not None: + set_env_from_config(execution_context) + ants_dir = os.environ.get("ANTSPATH") kwargs = {} cmd = ants_command_with_environment(["env"], use_runtime_env=False) - new_env = soma.subprocess.check_output(cmd, **kwargs).decode("utf-8").strip() + new_env = subprocess.check_output(cmd, **kwargs).decode("utf-8").strip() new_env = parse_env_lines(new_env) env = {} - for l in new_env: - name, val = l.strip().split("=", 1) - name = six.ensure_str(name) - val = six.ensure_str(val) + for line in new_env: + name, val = line.strip().split("=", 1) if name not in ("_", "SHLVL") and ( name not in os.environ or os.environ[name] != val ): @@ -102,35 +118,37 @@ def ants_env(): return env -class ANTSPopen(soma.subprocess.Popen): +class ANTSPopen(subprocess.Popen): """ Equivalent to Python subprocess.Popen for ANTS commands """ - def __init__(self, command, **kwargs): - cmd = ants_command_with_environment(command) + def __init__(self, command, execution_context=None, **kwargs): + cmd = ants_command_with_environment( + command, execution_context=execution_context + ) super(ANTSPopen, self).__init__(cmd, **kwargs) -def ants_call(command, **kwargs): +def ants_call(command, execution_context=None, **kwargs): """ Equivalent to Python subprocess.call for ANTS commands """ - cmd = ants_command_with_environment(command) - return soma.subprocess.call(cmd, **kwargs) + cmd = ants_command_with_environment(command, execution_context=execution_context) + return subprocess.call(cmd, **kwargs) -def ants_check_call(command, **kwargs): +def ants_check_call(command, execution_context=None, **kwargs): """ Equivalent to Python subprocess.check_call for ANTS commands """ - cmd = ants_command_with_environment(command) - return soma.subprocess.check_call(cmd, **kwargs) + cmd = ants_command_with_environment(command, execution_context=execution_context) + return subprocess.check_call(cmd, **kwargs) -def ants_check_output(command, **kwargs): +def ants_check_output(command, execution_context=None, **kwargs): """ Equivalent to Python subprocess.check_output for ANTS commands """ - cmd = ants_command_with_environment(command) - return soma.subprocess.check_output(cmd, **kwargs) + cmd = ants_command_with_environment(command, execution_context=execution_context) + return subprocess.check_output(cmd, **kwargs) diff --git a/capsul/in_context/freesurfer.py b/capsul/in_context/freesurfer.py index 1f7437aa6..3e1577201 100644 --- a/capsul/in_context/freesurfer.py +++ b/capsul/in_context/freesurfer.py @@ -1,18 +1,22 @@ # -*- coding: utf-8 -*- """ Specific subprocess-like functions to call Freesurfer taking into account -configuration stored in the activated configuration. -""" +configuration stored in the execution context configuration. + +Alternatively, without an ExecutionContext object, if environment variables are +properly set, the functions will use: -from __future__ import absolute_import +- FREESURFER_HOME +- FREESURFER_SETUP +- SUBJECTS_DIR +""" import os import os.path as osp -import soma.subprocess +import subprocess from soma.utils.env import parse_env_lines -from capsul import engine -import pipes -import six +from soma.controller import undefined + """ If this variable is set, it contains FS runtime env variables, @@ -21,7 +25,23 @@ freesurfer_runtime_env = None -def freesurfer_command_with_environment(command, use_runtime_env=True): +def set_env_from_config(execution_context): + """ + Set environment variables FSLDIR, FSL_CONFIG, FSL_PREFIX according to the + execution context configuration. + """ + fs_mod = getattr(execution_context, "freesurfer") + if fs_mod: + if fs_mod.setup_script is not undefined: + os.environ["FREESURFER_HOME"] = osp.dirname(fs_mod.setup_script) + os.environ["FREESURFER_SETUP"] = fs_mod.setup_script + if fs_mod.subjects_dir is not undefined: + os.environ["SUBJECTS_DIR"] = fs_mod.subjects_dir + + +def freesurfer_command_with_environment( + command, execution_context=None, use_runtime_env=True +): """ Given a Freesurfer command where first element is a command name without any path or prefix (e.g. "recon-all"). Returns the appropriate command to @@ -31,34 +51,24 @@ def freesurfer_command_with_environment(command, use_runtime_env=True): Using :func`freesurfer_env` is an alternative to this. """ + if execution_context is not None: + set_env_from_config(execution_context) + + cmd = command if use_runtime_env and freesurfer_runtime_env: c0 = list(osp.split(command[0])) c0 = osp.join(*c0) cmd = [c0] + command[1:] return cmd - fconf = engine.configurations.get("capsul.engine.module.freesurfer") - - if fconf: - freesurfer_script = fconf.get("setup") - - if freesurfer_script is not None and os.path.isfile(freesurfer_script): - freesurfer_dir = os.path.dirname(freesurfer_script) - - else: - freesurfer_dir = None + freesurfer_dir = os.environ.get("FREESURFER_HOME") + freesurfer_script = os.environ.get("FREESURFER_SETUP") - else: - freesurfer_dir = os.environ.get("FREESURFER_HOME") + if freesurfer_script is None and freesurfer_dir is not None: + freesurfer_script = os.path.join(freesurfer_dir, "SetUpFreeSurfer.sh") - if freesurfer_dir is not None: - freesurfer_script = os.path.join(freesurfer_dir, "SetUpFreeSurfer.sh") - - if not os.path.isfile(freesurfer_script): - freesurfer_script = None - - else: - freesurfer_script = None + if freesurfer_script is not None and not os.path.isfile(freesurfer_script): + freesurfer_script = None if freesurfer_dir is not None and freesurfer_script is not None: shell = os.environ.get("SHELL", "/bin/sh") @@ -74,6 +84,8 @@ def freesurfer_command_with_environment(command, use_runtime_env=True): ] else: + # the SetUpFreeSurfer.sh script is actually for bash, not sh ! + shell = osp.join(osp.dirname(shell), "bash") cmd = [ shell, "-c", @@ -86,7 +98,7 @@ def freesurfer_command_with_environment(command, use_runtime_env=True): return cmd -def freesurfer_env(): +def freesurfer_env(execution_context=None): """ get Freesurfer env variables by running the setup script in a separate bash process @@ -96,16 +108,17 @@ def freesurfer_env(): if freesurfer_runtime_env is not None: return freesurfer_runtime_env + if execution_context is not None: + set_env_from_config(execution_context) + kwargs = {} cmd = freesurfer_command_with_environment(["env"], use_runtime_env=False) - new_env = soma.subprocess.check_output(cmd, **kwargs).decode("utf-8").strip() + new_env = subprocess.check_output(cmd, **kwargs).decode("utf-8").strip() new_env = parse_env_lines(new_env) env = {} - for l in new_env: - name, val = l.strip().split("=", 1) - name = six.ensure_str(name) - val = six.ensure_str(val) + for line in new_env: + name, val = line.strip().split("=", 1) if name not in ("_", "SHLVL") and ( name not in os.environ or os.environ[name] != val @@ -117,35 +130,68 @@ def freesurfer_env(): return env -class FreesurferPopen(soma.subprocess.Popen): +class FreesurferPopen(subprocess.Popen): """ Equivalent to Python subprocess.Popen for Freesurfer commands """ - def __init__(self, command, **kwargs): - cmd = freesurfer_command_with_environment(command) - super(FreesurferPopen, self).__init__(cmd, **kwargs) - - -def freesurfer_call(command, **kwargs): + def __init__(self, command, execution_context=None, **kwargs): + cmd = freesurfer_command_with_environment( + command, execution_context=execution_context + ) + env = freesurfer_env() # execution_context is not needed any longer + # since global env variables have been set + if "env" in kwargs: + env = dict(env) + env.update(kwargs["env"]) + kwargs = dict(kwargs) + del kwargs["env"] + super().__init__(cmd, env=env, **kwargs) + + +def freesurfer_call(command, execution_context=None, **kwargs): """ Equivalent to Python subprocess.call for Freesurfer commands """ - cmd = freesurfer_command_with_environment(command) - return soma.subprocess.call(cmd, **kwargs) - - -def freesurfer_check_call(command, **kwargs): + cmd = freesurfer_command_with_environment( + command, execution_context=execution_context + ) + env = freesurfer_env() + if "env" in kwargs: + env = dict(env) + env.update(kwargs["env"]) + kwargs = dict(kwargs) + del kwargs["env"] + return subprocess.call(cmd, env=env, **kwargs) + + +def freesurfer_check_call(command, execution_context=None, **kwargs): """ Equivalent to Python subprocess.check_call for Freesurfer commands """ - cmd = freesurfer_command_with_environment(command) - return soma.subprocess.call(cmd, **kwargs) - - -def freesurfer_check_output(command, **kwargs): + cmd = freesurfer_command_with_environment( + command, execution_context=execution_context + ) + env = freesurfer_env() + if "env" in kwargs: + env = dict(env) + env.update(kwargs["env"]) + kwargs = dict(kwargs) + del kwargs["env"] + return subprocess.call(cmd, env=env, **kwargs) + + +def freesurfer_check_output(command, execution_context=None, **kwargs): """ Equivalent to Python subprocess.check_output for Freesurfer commands """ - cmd = freesurfer_command_with_environment(command) - return soma.subprocess.check_output(cmd, **kwargs) + cmd = freesurfer_command_with_environment( + command, execution_context=execution_context + ) + env = freesurfer_env() + if "env" in kwargs: + env = dict(env) + env.update(kwargs["env"]) + kwargs = dict(kwargs) + del kwargs["env"] + return subprocess.check_output(cmd, env=env, **kwargs) diff --git a/capsul/in_context/fsl.py b/capsul/in_context/fsl.py index 5f2d74c0a..08841f413 100644 --- a/capsul/in_context/fsl.py +++ b/capsul/in_context/fsl.py @@ -1,16 +1,20 @@ # -*- coding: utf-8 -*- """ Specific subprocess-like functions to call FSL taking into account -configuration stored in ExecutionContext. To functions and class in -this module it is mandatory to activate an ExecutionContext (using a -with statement). For instance:: +configuration stored in ExecutionContext. +:: - from capsul.engine import capsul_engine - from capsul.in_context.fsl import fsl_check_call + from capsul.api import Process + from capsul.in_context.fsl import fsl_check_call - ce = capsul_engine() - with ce: - fsl_check_call(['bet', '/somewhere/myimage.nii']) + ce = Capsul() + # .. configure it ... + Class MyProcess(Process): + + # [declare fields etc] ... + + def execute(self, execution_context): + fsl_check_call(['bet', '-h'], execution_context=execution_context) For calling FSL command with this module, the first arguent of command line must be the FSL executable without any path nor prefix. @@ -18,35 +22,59 @@ Neurodebian FSL commands are prefixed with "fsl5.0-". The appropriate path and eventually prefix are added from the configuration of the ExecutionContext. -""" -from __future__ import absolute_import +Alternatively, without an ExecutionContext object, if environment variables are +properly set, the functions will use: + +- FSL_PREFIX +- FSLDIR +- FSL_CONFIG +""" import os import os.path as osp -import soma.subprocess -import six +import subprocess -from traits.api import Undefined -from soma.path import find_in_path +from soma.controller import undefined from soma.utils.env import parse_env_lines """ -If this variable is set, it contains FS runtime env variables, allowing to run directly freesurfer commands from this process. +If this variable is set, it contains FSL runtime env variables, allowing to run +directly FSL commands from this process. """ fsl_runtime_env = None -def fsl_command_with_environment(command, use_prefix=True, use_runtime_env=True): +def set_env_from_config(execution_context): + """ + Set environment variables FSLDIR, FSL_CONFIG, FSL_PREFIX according to the + execution context configuration. + """ + fsl_mod = getattr(execution_context, "fsl") + if fsl_mod: + if fsl_mod.directory is not undefined: + os.environ["FSLDIR"] = fsl_mod.directory + if fsl_mod.setup_script is not undefined: + os.environ["FSL_CONFIG"] = fsl_mod.setup_script + if fsl_mod.prefix is not undefined: + os.environ["FSL_PREFIX"] = fsl_mod.prefix + + +def fsl_command_with_environment( + command, execution_context=None, use_prefix=True, use_runtime_env=True +): """ 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 FSL configuration stored in the activated ExecutionContext. - Usinfg :func`fsl_env` is an alternative to this. + Using :func:`fsl_env` is an alternative to this. """ + if execution_context is not None: + set_env_from_config(execution_context) + if use_prefix: fsl_prefix = os.environ.get("FSL_PREFIX", "") else: @@ -93,7 +121,7 @@ def fsl_command_with_environment(command, use_prefix=True, use_runtime_env=True) return cmd -def fsl_env(): +def fsl_env(execution_context=None): """ get FSL env variables by running the setup script in a separate bash process @@ -103,6 +131,9 @@ def fsl_env(): if fsl_runtime_env is not None: return fsl_runtime_env + if execution_context is not None: + set_env_from_config(execution_context) + fsl_config = os.environ.get("FSL_CONFIG") fsl_dir = os.environ.get("FSLDIR") kwargs = {} @@ -120,13 +151,11 @@ def fsl_env(): cmd = fsl_command_with_environment( ["env"], use_prefix=False, use_runtime_env=False ) - new_env = soma.subprocess.check_output(cmd, **kwargs).decode("utf-8").strip() + new_env = subprocess.check_output(cmd, **kwargs).decode("utf-8").strip() new_env = parse_env_lines(new_env) env = {} - for l in new_env: - name, val = l.strip().split("=", 1) - name = six.ensure_str(name) - val = six.ensure_str(val) + for line in new_env: + name, val = line.strip().split("=", 1) if name not in ("_", "SHLVL") and ( name not in os.environ or os.environ[name] != val ): @@ -140,59 +169,60 @@ def fsl_env(): return env -class FslPopen(soma.subprocess.Popen): +class FslPopen(subprocess.Popen): """ Equivalent to Python subprocess.Popen for FSL commands """ - def __init__(self, command, **kwargs): - cmd = fsl_command_with_environment(command) - env = fsl_env() + def __init__(self, command, execution_context=None, **kwargs): + cmd = fsl_command_with_environment(command, execution_context=execution_context) + env = fsl_env() # execution_context is not needed any longer + # since global env variables have been set if "env" in kwargs: env = dict(env) env.update(kwargs["env"]) kwargs = dict(kwargs) del kwargs["env"] - super(FslPopen, self).__init__(cmd, env=env, **kwargs) + super().__init__(cmd, env=env, **kwargs) -def fsl_call(command, **kwargs): +def fsl_call(command, execution_context=None, **kwargs): """ Equivalent to Python subprocess.call for FSL commands """ - cmd = fsl_command_with_environment(command) + cmd = fsl_command_with_environment(command, execution_context=execution_context) env = fsl_env() if "env" in kwargs: env = dict(env) env.update(kwargs["env"]) kwargs = dict(kwargs) del kwargs["env"] - return soma.subprocess.call(cmd, env=env, **kwargs) + return subprocess.call(cmd, env=env, **kwargs) -def fsl_check_call(command, **kwargs): +def fsl_check_call(command, execution_context=None, **kwargs): """ Equivalent to Python subprocess.check_call for FSL commands """ - cmd = fsl_command_with_environment(command) + cmd = fsl_command_with_environment(command, execution_context=execution_context) env = fsl_env() if "env" in kwargs: env = dict(env) env.update(kwargs["env"]) kwargs = dict(kwargs) del kwargs["env"] - return soma.subprocess.check_call(cmd, env=env, **kwargs) + return subprocess.check_call(cmd, env=env, **kwargs) -def fsl_check_output(command, **kwargs): +def fsl_check_output(command, execution_context=None, **kwargs): """ Equivalent to Python subprocess.check_output for FSL commands """ - cmd = fsl_command_with_environment(command) + cmd = fsl_command_with_environment(command, execution_context=execution_context) env = fsl_env() if "env" in kwargs: env = dict(env) env.update(kwargs["env"]) kwargs = dict(kwargs) del kwargs["env"] - return soma.subprocess.check_output(cmd, env=env, **kwargs) + return subprocess.check_output(cmd, env=env, **kwargs) diff --git a/capsul/in_context/matlab.py b/capsul/in_context/matlab.py new file mode 100644 index 000000000..28859ed9c --- /dev/null +++ b/capsul/in_context/matlab.py @@ -0,0 +1,85 @@ +# -*- coding: utf-8 -*- +""" +Specific subprocess-like functions to call Matlab taking into account +configuration stored in ExecutionContext. +""" + +import os +import subprocess +from soma.controller import undefined + + +def set_env_from_config(execution_context): + """ + Set environment variables according to the + execution context configuration. + """ + matlab_mod = getattr(execution_context, "matlab") + if matlab_mod: + if matlab_mod.executable is not undefined: + os.environ["MATLAB_EXECUTABLE"] = matlab_mod.executable + if matlab_mod.mcr_directory is not undefined: + os.environ["MATLAB_MCR_DIRECTORY"] = matlab_mod.mcr_directory + + +def matlab_command(command, execution_context=None): + if execution_context is not None: + set_env_from_config(execution_context) + + cmd = command + mexe = os.environ.get("MATLAB_EXECUTABLE") + if mexe: + cmd = [mexe] + command[1:] + return cmd + + +class MatlabPopen(subprocess.Popen): + """ + Equivalent to Python subprocess.Popen for Matlab + """ + + def __init__(self, cmd, execution_context=None, **kwargs): + cmd = matlab_command(cmd, execution_context=execution_context) + super(MatlabPopen, self).__init__(cmd, **kwargs) + + +def matlab_call(cmd, execution_context=None, **kwargs): + """ + Equivalent to Python subprocess.call for Matlab + """ + cmd = matlab_command(cmd, execution_context=execution_context) + return subprocess.call(cmd, **kwargs) + + +def matlab_check_call(cmd, execution_context=None, **kwargs): + """ + Equivalent to Python subprocess.check_call for Matlab + """ + cmd = matlab_command(cmd, execution_context=execution_context) + return subprocess.check_call(cmd, **kwargs) + + +def matlab_check_output(cmd, execution_context=None, **kwargs): + """ + Equivalent to Python subprocess.check_output for Matlab + """ + cmd = matlab_command(cmd, execution_context=execution_context) + return subprocess.check_output(cmd, **kwargs) + + +if __name__ == "__main__": + from capsul.api import Capsul + import tempfile + + c = Capsul() + c.config.builtin.add_module("matlab") + c.config.builtin.matlab.directory = "/casa/matlab" + c.config.builtin.matlab.mcr_directory = "/casa/matlab/mcr/v97" + + batch = tempfile.NamedTemporaryFile(suffix=".m") + batch.write("fprintf(1, '%s', spm('dir'));") + batch.flush() + p = c.executable("nipype.interfaces.spm.Segment") + matlab_call( + ["matlab", batch.name], execution_context=c.engine().execution_context(p) + ) diff --git a/capsul/in_context/mrtrix.py b/capsul/in_context/mrtrix.py index eb36a2bee..b3de978b5 100644 --- a/capsul/in_context/mrtrix.py +++ b/capsul/in_context/mrtrix.py @@ -1,35 +1,33 @@ # -*- coding: utf-8 -*- """ Specific subprocess-like functions to call mrtrix taking into account -configuration stored in ExecutionContext. To functions and class in -this module it is mandatory to activate an ExecutionContext (using a -with statement). For instance:: - - from capsul.engine import capsul_engine - from capsul.in_context.mrtrix import mrtrix_check_call - - ce = capsul_engine() - with ce: - mrtrix_check_call(['mrinfo', '/somewhere/myimage.nii']) - -For calling mrtrix command with this module, the first argument of -command line must be the mrtrix executable without any path. -The appropriate path is added from the configuration -of the ExecutionContext. +configuration stored in ExecutionContext. """ -from __future__ import absolute_import - import os import os.path as osp -import soma.subprocess +import subprocess from soma.utils.env import parse_env_lines -import six +from soma.controller import undefined + mrtrix_runtime_env = None -def mrtrix_command_with_environment(command, use_runtime_env=True): +def set_env_from_config(execution_context): + """ + Set environment variables according to the + execution context configuration. + """ + mrtrix_mod = getattr(execution_context, "mrtrix") + if mrtrix_mod: + if mrtrix_mod.directory is not undefined: + os.environ["MRTRIXPATH"] = mrtrix_mod.directory + + +def mrtrix_command_with_environment( + command, execution_context=None, use_runtime_env=True +): """ Given an mrtrix command where first element is a command name without any path. Returns the appropriate command to call taking into account @@ -37,6 +35,9 @@ def mrtrix_command_with_environment(command, use_runtime_env=True): activated ExecutionContext. """ + if execution_context is not None: + set_env_from_config(execution_context) + if use_runtime_env and mrtrix_runtime_env: c0 = list(osp.split(command[0])) c0 = osp.join(*c0) @@ -44,6 +45,7 @@ def mrtrix_command_with_environment(command, use_runtime_env=True): return cmd mrtrix_dir = os.environ.get("MRTRIXPATH") + cmd = command if mrtrix_dir: shell = os.environ.get("SHELL", "/bin/sh") if shell.endswith("csh"): @@ -68,7 +70,7 @@ def mrtrix_command_with_environment(command, use_runtime_env=True): return cmd -def mrtrix_env(): +def mrtrix_env(execution_context=None): """ get mrtrix env variables process @@ -78,17 +80,18 @@ def mrtrix_env(): if mrtrix_runtime_env is not None: return mrtrix_runtime_env + if execution_context is not None: + set_env_from_config(execution_context) + mrtrix_dir = os.environ.get("MRTRIXPATH") kwargs = {} cmd = mrtrix_command_with_environment(["env"], use_runtime_env=False) - new_env = soma.subprocess.check_output(cmd, **kwargs).decode("utf-8").strip() + new_env = subprocess.check_output(cmd, **kwargs).decode("utf-8").strip() new_env = parse_env_lines(new_env) env = {} - for l in new_env: - name, val = l.strip().split("=", 1) - name = six.ensure_str(name) - val = six.ensure_str(val) + for line in new_env: + name, val = line.strip().split("=", 1) if name not in ("_", "SHLVL") and ( name not in os.environ or os.environ[name] != val ): @@ -102,35 +105,37 @@ def mrtrix_env(): return env -class MrtrixPopen(soma.subprocess.Popen): +class MrtrixPopen(subprocess.Popen): """ Equivalent to Python subprocess.Popen for mrtrix commands """ - def __init__(self, command, **kwargs): - cmd = mrtrix_command_with_environment(command) + def __init__(self, command, execution_context=None, **kwargs): + cmd = mrtrix_command_with_environment( + command, execution_context=execution_context + ) super(MrtrixPopen, self).__init__(cmd, **kwargs) -def mrtrix_call(command, **kwargs): +def mrtrix_call(command, execution_context=None, **kwargs): """ Equivalent to Python subprocess.call for mrtrix commands """ - cmd = mrtrix_command_with_environment(command) - return soma.subprocess.call(cmd, **kwargs) + cmd = mrtrix_command_with_environment(command, execution_context=execution_context) + return subprocess.call(cmd, **kwargs) -def mrtrix_check_call(command, **kwargs): +def mrtrix_check_call(command, execution_context=None, **kwargs): """ Equivalent to Python subprocess.check_call for mrtrix commands """ - cmd = mrtrix_command_with_environment(command) - return soma.subprocess.check_call(cmd, **kwargs) + cmd = mrtrix_command_with_environment(command, execution_context=execution_context) + return subprocess.check_call(cmd, **kwargs) -def mrtrix_check_output(command, **kwargs): +def mrtrix_check_output(command, execution_context=None, **kwargs): """ Equivalent to Python subprocess.check_output for mrtrix commands """ - cmd = mrtrix_command_with_environment(command) - return soma.subprocess.check_output(cmd, **kwargs) + cmd = mrtrix_command_with_environment(command, execution_context=execution_context) + return subprocess.check_output(cmd, **kwargs) diff --git a/capsul/in_context/nipype.py b/capsul/in_context/nipype.py deleted file mode 100644 index 25292bd7f..000000000 --- a/capsul/in_context/nipype.py +++ /dev/null @@ -1,166 +0,0 @@ -# -*- coding: utf-8 -*- - -import os -import os.path as osp -import tempfile - - -def configure_all(): - """ - Configure nipye for all known software interfaces their configuration - is present in os.environ. This environment must have been set by the - CapsulEngine mechanism. - """ - - configure_matlab() - configure_spm() - configure_fsl() - configure_freesurfer() - configure_afni() - configure_ants() - configure_mrtrix() - - -def configure_spm(): - """ - Configure Nipype SPM interface if CapsulEngine had been used to set - the appropriate configuration variables in os.environ. - """ - from . import spm as spmc - - standalone = os.environ.get("SPM_STANDALONE") == "yes" - if standalone: - from nipype.interfaces import spm - - spm_cmd = spmc.spm_command(None) - # set_mlab_paths() writes a file "pyscript.m" in the current directory. - # This is bad but we cannot do anything about it. So let's run it - # from a temp directory. - cwd = os.getcwd() - with tempfile.TemporaryDirectory() as tmpdir: - os.chdir(tmpdir) - spm.SPMCommand.set_mlab_paths( - matlab_cmd=" ".join(spm_cmd + ["script"]), use_mcr=True - ) - os.chdir(cwd) - - else: - # Matlab spm version - - spm_directory = os.environ.get("SPM_DIRECTORY") - if not spm_directory: - spm_directory = os.environ.get("SPM_HOME") - if spm_directory: - from nipype.interfaces import matlab - from nipype.interfaces import spm - - # set_mlab_paths() writes a file "pyscript.m" in the current - # directory. - # This is bad but we cannot do anything about it. So let's run it - # from a temp directory. - cwd = os.getcwd() - with tempfile.TemporaryDirectory() as tmpdir: - os.chdir(tmpdir) - matlab.MatlabCommand.set_default_paths( - [spm_directory] - ) # + add_to_default_matlab_path) - spm.SPMCommand.set_mlab_paths(matlab_cmd="", use_mcr=False) - os.chdir(cwd) - - -def configure_matlab(): - """ - Configure matlab for nipype - """ - - from capsul import engine - - conf = engine.configurations.get("capsul.engine.module.matlab") - if conf and conf.get("executable"): - matlab_exe = conf["executable"] - - from nipype.interfaces import matlab - - matlab.MatlabCommand.set_default_matlab_cmd( - matlab_exe + " -nodesktop -nosplash" - ) - - -def configure_fsl(): - """ - Configure FSL for nipype - """ - from capsul import engine - - conf = engine.configurations.get("capsul.engine.module.fsl") - if conf: - from capsul.in_context import fsl as fslrun - - env = fslrun.fsl_env() - for var, value in env.items(): - os.environ[var] = value - - -def configure_freesurfer(): - """ - Configure Freesurfer for nipype - """ - from capsul import engine - - conf = engine.configurations.get("capsul.engine.module.freesurfer") - if conf: - subjects_dir = conf.get("subjects_dir") - if subjects_dir: - from nipype.interfaces import freesurfer - - freesurfer.FSCommand.set_default_subjects_dir(subjects_dir) - from capsul.in_context import freesurfer as fsrun - - env = fsrun.freesurfer_env() - for var, value in env.items(): - os.environ[var] = value - - -def configure_afni(): - """ - Configure AFNI for nipype - """ - from capsul import engine - - conf = engine.configurations.get("capsul.engine.module.afni") - if conf: - from capsul.in_context import afni as afnirun - - env = afnirun.afni_env() - for var, value in env.items(): - os.environ[var] = value - - -def configure_ants(): - """ - Configure ANTS for nipype - """ - from capsul import engine - - conf = engine.configurations.get("capsul.engine.module.ants") - if conf: - from capsul.in_context import ants as antsrun - - env = antsrun.ants_env() - for var, value in env.items(): - os.environ[var] = value - - -def configure_mrtrix(): - """ - Configure mrtrix for nipype - """ - from capsul import engine - - conf = engine.configurations.get("capsul.engine.module.mrtrix") - if conf: - from capsul.in_context import mrtrix as mrtrixrun - - env = mrtrixrun.mrtrix_env() - for var, value in env.items(): - os.environ[var] = value diff --git a/capsul/in_context/spm.py b/capsul/in_context/spm.py index 92fd205ba..d0a00b11e 100644 --- a/capsul/in_context/spm.py +++ b/capsul/in_context/spm.py @@ -1,31 +1,36 @@ # -*- coding: utf-8 -*- """ Specific subprocess-like functions to call SPM taking into account -configuration stored in ExecutionContext. To functions and class in -this module it is mandatory to activate an ExecutionContext (using a -with statement). For instance:: - - from capsul.engine import capsul_engine - from capsul.in_context.spm import spm_check_call - - ce = capsul_engine() - with ce: - spm_check_call(spm_batch_filename) - -For calling SPM command with this module, the first arguent of -command line must be the SPM batch file to execute with Matlab. +configuration stored in ExecutionContext. """ -from __future__ import absolute_import, print_function - import glob import os import os.path as osp +import subprocess +from soma.controller import undefined + + +def set_env_from_config(execution_context): + """ + Set environment variables according to the + execution context configuration. + """ + spm_mod = getattr(execution_context, "spm") + if spm_mod: + if spm_mod.directory is not undefined: + os.environ["SPM_DIRECTORY"] = spm_mod.directory + if spm_mod.standalone is not undefined: + os.environ["SPM_STANDALONE"] = str(int(spm_mod.standalone)) + from . import matlab + + matlab.set_env_from_config(execution_context) -import soma.subprocess +def spm_command(spm_batch_filename, execution_context=None): + if execution_context is not None: + set_env_from_config(execution_context) -def spm_command(spm_batch_filename): if os.environ.get("SPM_STANDALONE") == "yes": if spm_batch_filename is not None: # Check that batch file exists and raise appropriate error if @@ -54,48 +59,35 @@ def spm_command(spm_batch_filename): return cmd -class SPMPopen(soma.subprocess.Popen): +class SPMPopen(subprocess.Popen): """ Equivalent to Python subprocess.Popen for SPM batch """ - def __init__(self, spm_batch_filename, **kwargs): - cmd = spm_command(spm_batch_filename) + def __init__(self, spm_batch_filename, execution_context=None, **kwargs): + cmd = spm_command(spm_batch_filename, execution_context=execution_context) super(SPMPopen, self).__init__(cmd, **kwargs) -def spm_call(spm_batch_filename, **kwargs): +def spm_call(spm_batch_filename, execution_context=None, **kwargs): """ Equivalent to Python subprocess.call for SPM batch """ - cmd = spm_command(spm_batch_filename) - return soma.subprocess.call(cmd, **kwargs) + cmd = spm_command(spm_batch_filename, execution_context=execution_context) + return subprocess.call(cmd, **kwargs) -def spm_check_call(spm_batch_filename, **kwargs): +def spm_check_call(spm_batch_filename, execution_context=None, **kwargs): """ Equivalent to Python subprocess.check_call for SPM batch """ - cmd = spm_command(spm_batch_filename) - return soma.subprocess.check_call(cmd, **kwargs) + cmd = spm_command(spm_batch_filename, execution_context=execution_context) + return subprocess.check_call(cmd, **kwargs) -def spm_check_output(spm_batch_filename, **kwargs): +def spm_check_output(spm_batch_filename, execution_context=None, **kwargs): """ Equivalent to Python subprocess.check_output for SPM batch """ - cmd = spm_command(spm_batch_filename) - return soma.subprocess.check_output(cmd, **kwargs) - - -if __name__ == "__main__": - from capsul.api import capsul_engine - import tempfile - - ce = capsul_engine() - ce.global_config.spm.directory = "/casa/spm12_standalone" - with ce: - batch = tempfile.NamedTemporaryFile(suffix=".m") - batch.write("fprintf(1, '%s', spm('dir'));") - batch.flush() - spm_call(batch.name) + cmd = spm_command(spm_batch_filename, execution_context=execution_context) + return subprocess.check_output(cmd, **kwargs)