Skip to content

Commit

Permalink
Adapt module function check for EnvironmentModules
Browse files Browse the repository at this point in the history
Default check_module_function tests that module command is called from
module shell function. With EnvironmentModules v4+, module command is
usually called from the _module_raw shell function.

This commit adds a specific version of check_module_function for
EnvironmentModules class. Module command is first checked within
_module_raw shell function definition. If not found, default test (that
checks module function) is run.

Adapt "test_module_mismatch" unit test to specifically check module
command definition with EnvironmentModules.

Fixes #4368
  • Loading branch information
xdelaruelle committed Oct 29, 2023
1 parent 6fccffe commit 85f5f5e
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 1 deletion.
23 changes: 23 additions & 0 deletions easybuild/tools/modules.py
Original file line number Diff line number Diff line change
Expand Up @@ -1328,6 +1328,29 @@ class EnvironmentModules(EnvironmentModulesTcl):
MAX_VERSION = None
VERSION_REGEXP = r'^Modules\s+Release\s+(?P<version>\d\S*)\s'

def check_module_function(self, allow_mismatch=False, regex=None):
"""Check whether selected module tool matches 'module' function definition."""
# Modules 5.1.0+: module command is called from _module_raw shell function
# Modules 4.2.0..5.0.1: module command is called from _module_raw shell function if it has
# been initialized in an interactive shell session (i.e., a session attached to a tty)
if self.testing:
if '_module_raw' in os.environ:
out, ec = os.environ['_module_raw'], 0
else:
out, ec = None, 1
else:
cmd = "type _module_raw"
out, ec = run_cmd(cmd, simple=False, log_ok=False, log_all=False, force_in_dry_run=True, trace=False)

if regex is None:
regex = r".*%s" % os.path.basename(self.cmd)
mod_cmd_re = re.compile(regex, re.M)

if ec == 0 and mod_cmd_re.search(out):
self.log.debug("Found pattern '%s' in defined 'module' function." % mod_cmd_re.pattern)
else:
super(EnvironmentModules, self).check_module_function(allow_mismatch, regex)

def check_module_output(self, cmd, stdout, stderr):
"""Check output of 'module' command, see if if is potentially invalid."""
if "_mlstatus = False" in stdout:
Expand Down
1 change: 1 addition & 0 deletions easybuild/tools/run.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
"sysctl -n machdep.cpu.brand_string", # used in get_cpu_model (OS X)
"sysctl -n machdep.cpu.vendor", # used in get_cpu_vendor (OS X)
"type module", # used in ModulesTool.check_module_function
"type _module_raw", # used in EnvironmentModules.check_module_function
"ulimit -u", # used in det_parallelism
]

Expand Down
15 changes: 14 additions & 1 deletion test/framework/modulestool.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
from easybuild.tools import modules, StrictVersion
from easybuild.tools.build_log import EasyBuildError
from easybuild.tools.filetools import read_file, which, write_file
from easybuild.tools.modules import Lmod
from easybuild.tools.modules import EnvironmentModules, Lmod
from test.framework.utilities import init_config


Expand Down Expand Up @@ -108,6 +108,19 @@ def test_environment_command(self):

def test_module_mismatch(self):
"""Test whether mismatch detection between modules tool and 'module' function works."""
# redefine 'module' and '_module_raw' function (deliberate mismatch with used module
# command in EnvironmentModules)
os.environ['_module_raw'] = "() { eval `/usr/share/Modules/libexec/foo.tcl' bash $*`;\n}"
os.environ['module'] = "() { _module_raw \"$@\" 2>&1;\n}"
error_regex = ".*pattern .* not found in defined 'module' function"
self.assertErrorRegex(EasyBuildError, error_regex, EnvironmentModules, testing=True)

# redefine '_module_raw' function with correct module command
os.environ['_module_raw'] = "() { eval `/usr/share/Modules/libexec/modulecmd.tcl' bash $*`;\n}"
mt = EnvironmentModules(testing=True)
self.assertIsInstance(mt.loaded_modules(), list) # dummy usage
del os.environ['_module_raw']

# redefine 'module' function (deliberate mismatch with used module command in MockModulesTool)
os.environ['module'] = "() { eval `/tmp/Modules/$MODULE_VERSION/bin/modulecmd bash $*`\n}"
error_regex = ".*pattern .* not found in defined 'module' function"
Expand Down

0 comments on commit 85f5f5e

Please sign in to comment.