Skip to content

Commit 928d1f3

Browse files
committed
reworked config modules activation in an execution context
and ease use of external software by re-introducing in_context (#338, #335)
1 parent b01a367 commit 928d1f3

22 files changed

+526
-475
lines changed

capsul/config/afni.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from .configuration import ModuleConfiguration
2-
from soma.controller import Directory, undefined, File, field
2+
from soma.controller import Directory, undefined, field
33

44

55
class AfniConfiguration(ModuleConfiguration):
@@ -15,11 +15,11 @@ def is_valid_config(self, requirements):
1515
return False
1616
return True
1717

18+
@staticmethod
19+
def init_execution_context(execution_context):
20+
"""
21+
Configure execution (env variables) from a configured execution context
22+
"""
23+
from capsul.in_context import afni
1824

19-
def init_execution_context(execution_context):
20-
"""
21-
Configure an execution context given a capsul_engine and some requirements.
22-
"""
23-
config = execution_context.config["modules"]["afni"]
24-
execution_context.afni = AfniConfiguration()
25-
execution_context.afni.import_from_dict(config)
25+
afni.set_env_from_config(execution_context)

capsul/config/ants.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from .configuration import ModuleConfiguration
2-
from soma.controller import Directory, undefined, File, field
2+
from soma.controller import Directory, undefined, field
33

44

55
class AntsConfiguration(ModuleConfiguration):
@@ -15,11 +15,11 @@ def is_valid_config(self, requirements):
1515
return False
1616
return True
1717

18+
@staticmethod
19+
def init_execution_context(execution_context):
20+
"""
21+
Configure execution (env variables) from a configured execution context
22+
"""
23+
from capsul.in_context import ants
1824

19-
def init_execution_context(execution_context):
20-
"""
21-
Configure an execution context given a capsul_engine and some requirements.
22-
"""
23-
config = execution_context.config["modules"]["ants"]
24-
execution_context.ants = AntsConfiguration()
25-
execution_context.ants.import_from_dict(config)
25+
ants.set_env_from_config(execution_context)

capsul/config/axon.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -50,12 +50,3 @@ def axon_default_shared_dir():
5050
@staticmethod
5151
def axon_default_version():
5252
return axon_default_version()
53-
54-
55-
def init_execution_context(execution_context):
56-
"""
57-
Configure an execution context given a capsul_engine and some requirements.
58-
"""
59-
config = execution_context.config["modules"]["axon"]
60-
execution_context.axon = AxonConfiguration()
61-
execution_context.axon.import_from_dict(config)

capsul/config/configuration.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,9 @@ def add_module(self, module_name, allow_existing=False):
191191
doc=cls.__doc__,
192192
default_factory=OpenKeyDictController[cls],
193193
)
194+
if self.config_modules is undefined:
195+
self.config_modules = []
196+
self.config_modules.append(module_name)
194197

195198
if hasattr(cls, "module_dependencies"):
196199
module_dependencies = getattr(cls, "module_dependencies")

capsul/config/freesurfer.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,11 @@ def is_valid_config(self, requirements):
1616
return False
1717
return True
1818

19+
@staticmethod
20+
def init_execution_context(execution_context):
21+
"""
22+
Configure execution (env variables) from a configured execution context
23+
"""
24+
from capsul.in_context import freesurfer
1925

20-
def init_execution_context(execution_context):
21-
"""
22-
Configure an execution context given a capsul_engine and some requirements.
23-
"""
24-
config = execution_context.config["modules"]["freesurfer"]
25-
execution_context.freesurfer = FreesurferConfiguration()
26-
execution_context.freesurfer.import_from_dict(config)
26+
freesurfer.set_env_from_config(execution_context)

capsul/config/fsl.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,11 @@ def is_valid_config(self, requirements):
1717
return False
1818
return True
1919

20+
@staticmethod
21+
def init_execution_context(execution_context):
22+
"""
23+
Configure execution (env variables) from a configured execution context
24+
"""
25+
from capsul.in_context import fsl
2026

21-
def init_execution_context(execution_context):
22-
"""
23-
Configure an execution context given a capsul_engine and some requirements.
24-
"""
25-
config = execution_context.config["modules"]["fsl"]
26-
execution_context.fsl = FSLConfiguration()
27-
execution_context.fsl.import_from_dict(config)
27+
fsl.set_env_from_config(execution_context)

capsul/config/matlab.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,11 @@ def is_valid_config(self, requirements):
5050
return False
5151
return True
5252

53-
54-
def init_execution_context(execution_context):
55-
"""
56-
Configure an execution context given a capsul_engine and some requirements.
57-
"""
58-
config = execution_context.config["modules"]["matlab"]
59-
execution_context.matlab = MatlabConfiguration()
60-
execution_context.matlab.import_dict(config)
53+
@staticmethod
54+
def init_execution_context(execution_context):
55+
"""
56+
Configure execution (env variables) from a configured execution context
57+
"""
58+
from capsul.in_context import matlab
59+
60+
matlab.set_env_from_config(execution_context)

capsul/config/mrtrix.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
from .configuration import ModuleConfiguration
2+
from soma.controller import Directory, undefined, field
3+
4+
5+
class MRTrixConfiguration(ModuleConfiguration):
6+
"""MRTrix configuration module"""
7+
8+
version: str
9+
directory: Directory = field(optional=True)
10+
name = "mrtrix"
11+
12+
def is_valid_config(self, requirements):
13+
required_version = requirements.get("version")
14+
if required_version and getattr(self, "version", undefined) != required_version:
15+
return False
16+
return True
17+
18+
@staticmethod
19+
def init_execution_context(execution_context):
20+
"""
21+
Configure execution (env variables) from a configured execution context
22+
"""
23+
from capsul.in_context import mrtrix
24+
25+
mrtrix.set_env_from_config(execution_context)

capsul/config/nipype.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,7 +154,7 @@ def configure_freesurfer(context):
154154
freesurfer.FSCommand.set_default_subjects_dir(subjects_dir)
155155
from capsul.in_context import freesurfer as fsrun
156156

157-
env = fsrun.freesurfer_env()
157+
env = fsrun.freesurfer_env(execution_context=context)
158158
for var, value in env.items():
159159
os.environ[var] = value
160160

capsul/config/python.py

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,3 @@ def is_valid_config(self, requirements):
1616
if required_version and getattr(self, "version", undefined) != required_version:
1717
return False
1818
return True
19-
20-
21-
def init_execution_context(execution_context):
22-
"""
23-
Configure an execution context given a capsul_engine and some requirements.
24-
"""
25-
config = execution_context.config["modules"]["python"]
26-
execution_context.python = PythonConfiguration()
27-
execution_context.python.import_from_dict(config)

capsul/config/spm.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,11 @@ def is_valid_config(self, requirements):
2121
else:
2222
return {"matlab": {"mcr": False}}
2323

24+
@staticmethod
25+
def init_execution_context(execution_context):
26+
"""
27+
Configure execution (env variables) from a configured execution context
28+
"""
29+
from capsul.in_context import spm
2430

25-
def init_execution_context(execution_context):
26-
"""
27-
Configure an execution context given a capsul_engine and some requirements.
28-
"""
29-
config = execution_context.config["modules"]["spm"]
30-
execution_context.spm = SPMConfiguration()
31-
execution_context.spm.import_dict(config)
31+
spm.set_env_from_config(execution_context)

capsul/engine/__init__.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,9 @@ def execution_context(engine_label, engine_config, executable):
2727
for conf_item in ("dataset", "config_modules", "python_modules"):
2828
if conf_item in cdict:
2929
config[conf_item] = cdict[conf_item]
30-
execution_context = ExecutionContext(executable=executable, config=config)
30+
execution_context = ExecutionContext(
31+
executable=executable, config=config, activate_modules=False
32+
)
3133

3234
req_to_check = execution_context.executable_requirements(executable)
3335
done_req = [] # record requirements to avoid loops
@@ -60,7 +62,7 @@ def execution_context(engine_label, engine_config, executable):
6062
# now check we have only one module for each
6163
for module_name in needed_modules:
6264
valid_module_configs = valid_configs.get(module_name)
63-
if not valid_module_configs:
65+
if valid_module_configs is None:
6466
raise RuntimeError(
6567
f'Execution environment "{engine_label}" has no '
6668
f"valid configuration for module {module_name}"
@@ -81,6 +83,10 @@ def execution_context(engine_label, engine_config, executable):
8183
module_name, type_=ModuleConfiguration, override=True
8284
)
8385
setattr(execution_context, module_name, valid_config)
86+
87+
# FIXME: should be done only in real execution (server) situation
88+
execution_context.activate_modules_config()
89+
8490
return execution_context
8591

8692

capsul/execution_context.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,17 @@ class ExecutionContext(Controller):
2525
config_modules: list[str]
2626
dataset: OpenKeyDictController[Dataset]
2727

28-
def __init__(self, config=None, executable=None):
29-
mod_classes = []
28+
def __init__(self, config=None, executable=None, activate_modules=True):
29+
super().__init__()
3030
if config:
3131
python_modules = config.get("python_modules", ())
3232
for m in python_modules:
3333
importlib.import_module(m)
3434
config_modules = config.get("config_modules", ())
35+
self.config_modules = config_modules
3536
for m in config_modules:
3637
# The following function loads the appropriate module
3738
get_config_class(m)
38-
super().__init__()
3939
self.dataset = OpenKeyDictController[Dataset]()
4040
if config is not None:
4141
for k in list(config.keys()):
@@ -53,14 +53,17 @@ def __init__(self, config=None, executable=None):
5353
k = new_k
5454
if cls:
5555
self.add_field(k, cls, doc=cls.__doc__, default_factory=cls)
56-
mod_classes.append(cls)
5756
dataset = config.pop("dataset", None)
5857
if dataset:
5958
self.dataset = dataset
6059
self.import_dict(config)
6160
self.executable = executable
61+
if activate_modules:
62+
self.activate_modules_config()
6263

63-
for cls in mod_classes:
64+
def activate_modules_config(self):
65+
for cm in self.config_modules:
66+
cls = get_config_class(cm)
6467
if hasattr(cls, "init_execution_context"):
6568
cls.init_execution_context(self)
6669

capsul/in_context/__init__.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
# -*- coding: utf-8 -*-
22
"""
3-
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.
4-
Activating the context is normally done using the ``with`` statement on a :class:`~capsul.engine.CapsulEngine` object::
3+
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`).
4+
The notable difference is that they use an :class:`~capsul.execution_context.ExecutionContext` object instance to get configuration from.
5+
These functions are only run from within the :meth:`~capsul.process.Process.execute` method of a Process, which gets the context as a paremeter::
56
6-
from capsul.engine import capsul_engine
7+
from capsul.api import Process
78
from capsul.in_context.fsl import fsl_check_call
89
9-
ce = capsul_engine()
10+
ce = Capsul()
1011
# .. configure it ...
12+
Class MyProcess(Process):
1113
12-
with ce:
13-
fsl_check_call(['bet', '-h'])
14+
# [declare fields etc] ...
15+
16+
def execute(self, execution_context):
17+
fsl_check_call(['bet', '-h'], execution_context=execution_context)
1418
1519
"""

0 commit comments

Comments
 (0)