Skip to content

Commit 9354331

Browse files
author
Vasileios Karakasis
authored
Merge pull request #1611 from vkarak/bugfix/treat-conflicts-module-mappings
[bugfix] Treat conflicts in module mappings properly
2 parents 4aa8ac9 + 97b2859 commit 9354331

File tree

9 files changed

+75
-37
lines changed

9 files changed

+75
-37
lines changed

reframe/core/modules.py

Lines changed: 30 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ def __eq__(self, other):
8282
return self.name == other.name and self.version == other.version
8383

8484
def __repr__(self):
85-
return '%s(%s)' % (type(self).__name__, self.fullname)
85+
return f'{type(self).__name__}({self.fullname}, {self.collection})'
8686

8787
def __str__(self):
8888
return self.fullname
@@ -222,15 +222,20 @@ def load_module(self, name, force=False, collection=False):
222222
conflicting modules currently loaded. If module ``name`` refers to
223223
multiple real modules, all of the target modules will be loaded.
224224
:arg collection: The module is a "module collection" (TMod4 only)
225-
:returns: the list of unloaded modules as strings.
225+
:returns: A list of two-element tuples, where each tuple contains the
226+
module that was loaded and the list of modules that had to be
227+
unloaded first due to conflicts. This list will be normally of
228+
size one, but it can be longer if there is mapping that maps
229+
module ``name`` to multiple other modules.
226230
227231
.. versionchanged:: 3.3
228-
The ``collection`` argument was added.
232+
- The ``collection`` argument was added.
233+
- This function now returns a list of tuples.
229234
230235
'''
231236
ret = []
232237
for m in self.resolve_module(name):
233-
ret += self._load_module(m, force, collection)
238+
ret.append((m, self._load_module(m, force, collection)))
234239

235240
return ret
236241

@@ -349,37 +354,41 @@ def searchpath_remove(self, *dirs):
349354
return self._backend.searchpath_remove(*dirs)
350355

351356
def emit_load_commands(self, name, collection=False):
352-
'''Return the appropriate shell command for loading module ``name``.
357+
'''Return the appropriate shell commands for loading a module.
358+
359+
Module mappings are not taken into account by this function.
353360
354361
:arg name: The name of the module to load.
355362
:arg collection: The module is a "module collection" (TMod4 only)
356363
:returns: A list of shell commands.
357364
358365
.. versionchanged:: 3.3
359-
The ``collection`` argument was added.
366+
The ``collection`` argument was added and module mappings are no
367+
more taken into account by this function.
360368
361369
'''
362-
ret = []
363-
for name in self.resolve_module(name):
364-
cmds = self._backend.emit_load_instr(Module(name, collection))
365-
if cmds:
366-
ret.append(cmds)
367370

368-
return ret
371+
# We don't consider module mappings here, because we cannot treat
372+
# correctly possible conflicts
373+
return [self._backend.emit_load_instr(Module(name, collection))]
369374

370375
def emit_unload_commands(self, name, collection=False):
371-
'''Return the appropriate shell command for unloading module
372-
``name``.
376+
'''Return the appropriate shell commands for unloading a module.
377+
378+
Module mappings are not taken into account by this function.
379+
380+
:arg name: The name of the module to unload.
381+
:arg collection: The module is a "module collection" (TMod4 only)
382+
:returns: A list of shell commands.
383+
384+
.. versionchanged:: 3.3
385+
The ``collection`` argument was added and module mappings are no
386+
more taken into account by this function.
373387
374-
:rtype: List[str]
375388
'''
376-
ret = []
377-
for name in self.resolve_module(name):
378-
cmds = self._backend.emit_unload_instr(Module(name, collection))
379-
if cmds:
380-
ret.append(cmds)
381389

382-
return ret
390+
# See comment in emit_load_commands()
391+
return [self._backend.emit_unload_instr(Module(name, collection))]
383392

384393
def __str__(self):
385394
return str(self._backend)

reframe/core/runtime.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -212,16 +212,19 @@ def loadenv(*environs):
212212
env_snapshot = snapshot()
213213
commands = []
214214
for env in environs:
215-
for m in env.modules_detailed:
216-
conflicted = modules_system.load_module(**m, force=True)
217-
for c in conflicted:
218-
commands += modules_system.emit_unload_commands(c)
215+
for mod in env.modules_detailed:
216+
load_seq = modules_system.load_module(**mod, force=True)
217+
for m, conflicted in load_seq:
218+
for c in conflicted:
219+
commands += modules_system.emit_unload_commands(c)
219220

220-
commands += modules_system.emit_load_commands(**m)
221+
commands += modules_system.emit_load_commands(
222+
m, mod['collection']
223+
)
221224

222225
for k, v in env.variables.items():
223226
os.environ[k] = osext.expandvars(v)
224-
commands.append('export %s=%s' % (k, v))
227+
commands.append(f'export {k}={v}')
225228

226229
return env_snapshot, commands
227230

@@ -284,7 +287,7 @@ def __init__(self, config_file, sysname=None, options=None):
284287
_runtime_context = None
285288
else:
286289
site_config = config.load_config(config_file)
287-
site_config.select_subconfig(sysname)
290+
site_config.select_subconfig(sysname, ignore_resolve_errors=True)
288291
for opt, value in options.items():
289292
site_config.add_sticky_option(opt, value)
290293

unittests/modules/testmod_bar

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#%Module
22
proc ModulesHelp { } {
3-
Helper module for PyRegression unit tests
3+
Helper module for ReFrame unit tests
44
}
55

66
module-whatis { Helper module for ReFrame unit tests }

unittests/modules/testmod_boo

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#%Module
22
proc ModulesHelp { } {
3-
Helper module for PyRegression unit tests
3+
Helper module for ReFrame unit tests
44
}
55

66
module-whatis { Helper module for ReFrame unit tests }

unittests/modules/testmod_ext

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#%Module
2+
proc ModulesHelp { } {
3+
Helper module for ReFrame unit tests
4+
}
5+
6+
module-whatis { Helper module for ReFrame unit tests }
7+
8+
module load testmod_base
9+
module load testmod_bar

unittests/modules/testmod_foo

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#%Module
22
proc ModulesHelp { } {
3-
Helper module for PyRegression unit tests
3+
Helper module for ReFrame unit tests
44
}
55

66
module-whatis { Helper module for ReFrame unit tests }

unittests/test_environments.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,23 @@ def test_emit_loadenv_commands_with_confict(base_environ, user_runtime,
252252
assert expected_commands == rt.emit_loadenv_commands(env0)
253253

254254

255+
def test_emit_loadenv_commands_mapping_with_conflict(base_environ,
256+
user_runtime,
257+
modules_system):
258+
if modules_system.name == 'tmod4':
259+
pytest.skip('test scenario not valid for tmod4')
260+
261+
e0 = env.Environment(name='e0', modules=['testmod_ext'])
262+
ms = rt.runtime().modules_system
263+
ms.load_mapping('testmod_ext: testmod_ext testmod_foo')
264+
expected_commands = [
265+
ms.emit_load_commands('testmod_ext')[0],
266+
ms.emit_unload_commands('testmod_bar')[0],
267+
ms.emit_load_commands('testmod_foo')[0],
268+
]
269+
assert expected_commands == rt.emit_loadenv_commands(e0)
270+
271+
255272
def test_emit_loadenv_failure(user_runtime):
256273
snap = rt.snapshot()
257274
environ = env.Environment('test', modules=['testmod_foo', 'testmod_xxx'])

unittests/test_modules.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,13 +112,13 @@ def test_module_load_force(modules_system):
112112
modules_system.load_module('testmod_foo')
113113

114114
unloaded = modules_system.load_module('testmod_foo', force=True)
115-
assert 0 == len(unloaded)
115+
assert unloaded == [('testmod_foo', [])]
116116
assert modules_system.is_module_loaded('testmod_foo')
117117

118118
unloaded = modules_system.load_module('testmod_bar', force=True)
119119
assert modules_system.is_module_loaded('testmod_bar')
120120
assert not modules_system.is_module_loaded('testmod_foo')
121-
assert 'testmod_foo' in unloaded
121+
assert unloaded == [('testmod_bar', ['testmod_foo'])]
122122
assert 'TESTMOD_BAR' in os.environ
123123

124124

@@ -127,7 +127,7 @@ def test_module_load_force_collection(modules_system, module_collection):
127127
modules_system.load_module('testmod_bar')
128128
unloaded = modules_system.load_module(module_collection,
129129
force=True, collection=True)
130-
assert unloaded == []
130+
assert unloaded == [('test_collection', [])]
131131
assert modules_system.is_module_loaded('testmod_base')
132132
assert modules_system.is_module_loaded('testmod_foo')
133133

@@ -165,7 +165,7 @@ def test_module_available_all(modules_system):
165165
assert modules == []
166166
else:
167167
assert (modules == ['testmod_bar', 'testmod_base',
168-
'testmod_boo', 'testmod_foo'])
168+
'testmod_boo', 'testmod_ext', 'testmod_foo'])
169169

170170

171171
def test_module_available_substr(modules_system):

unittests/test_utility.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1429,8 +1429,8 @@ def test_find_modules(modules_system):
14291429
if modules_system.name == 'nomod':
14301430
assert found_modules == []
14311431
else:
1432-
assert found_modules == ['testmod_bar', 'testmod_base',
1433-
'testmod_boo', 'testmod_foo']*ntimes
1432+
assert found_modules == ['testmod_bar', 'testmod_base', 'testmod_boo',
1433+
'testmod_ext', 'testmod_foo']*ntimes
14341434

14351435

14361436
def test_find_modules_env_mapping(modules_system):

0 commit comments

Comments
 (0)