Skip to content

Python configuration loading should be made more robust #3708

Description

@vkarak

Consider the following test that parameterizes over a configuration parameter:

diff --git a/unittests/resources/checks/hellocheck.py b/unittests/resources/checks/hellocheck.py
index a383f3e77..00f7d9cc0 100644
--- a/unittests/resources/checks/hellocheck.py
+++ b/unittests/resources/checks/hellocheck.py
@@ -5,6 +5,15 @@
 
 import reframe as rfm
 import reframe.utility.sanity as sn
+from reframe.core.builtins import parameter
+from reframe.core.runtime import valid_sysenv_comb
+
+
+def config_parameterization(valid_systems, valid_prog_environs):
+    for sys, envs in valid_sysenv_comb(valid_systems, valid_prog_environs).items():
+        for env in envs:
+            if 'foo' in env.features:
+                yield sys, env
 
 
 @rfm.simple_test
@@ -14,6 +23,7 @@ class HelloTest(rfm.RegressionTest, pin_prefix=True):
     # All available systems are supported
     valid_systems = ['*']
     valid_prog_environs = ['*']
+    p = parameter(config_parameterization(valid_systems, valid_prog_environs))
     sourcepath = 'hello.c'
     tags = {'foo', 'bar'}
     maintainers = ['VK']

If you accidentally try to load it with the -C option (--config-file) instead of -c (--check-path), ReFrame will crash with a barely understandable error:

Traceback (most recent call last):
  File "/path/to/reframe/.venv/bin/reframe", line 10, in <module>
    sys.exit(main())
             ~~~~^^
  File "/path/to/reframe/reframe/core/logging.py", line 1148, in _fn
    return fn(*args, **kwargs)
  File "/path/to/reframe/reframe/frontend/cli.py", line 1025, in main
    site_config = config.load_config(*conf_files)
  File "/path/to/reframe/reframe/core/config.py", line 708, in load_config
    ret.load_config_python(f)
    ~~~~~~~~~~~~~~~~~~~~~~^^^
  File "/path/to/reframe/reframe/core/config.py", line 346, in load_config_python
    mod = util.import_module_from_file(filename, load_parents=True)
  File "/path/to/reframe/reframe/utility/__init__.py", line 183, in import_module_from_file
    return _import_module_from_file(filename, force, parent_module)
  File "/path/to/reframe/reframe/utility/__init__.py", line 117, in _import_module_from_file
    return importlib.import_module(module_name)
           ~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^
  File "/opt/homebrew/Cellar/python@3.13/3.13.3_1/Frameworks/Python.framework/Versions/3.13/lib/python3.13/importlib/__init__.py", line 88, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
           ~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "<frozen importlib._bootstrap>", line 1387, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1360, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1331, in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 935, in _load_unlocked
  File "<frozen importlib._bootstrap_external>", line 1026, in exec_module
  File "<frozen importlib._bootstrap>", line 488, in _call_with_frames_removed
  File "/path/to/reframe/unittests/resources/checks/hellocheck.py", line 20, in <module>
    class HelloTest(rfm.RegressionTest, pin_prefix=True):
    ...<12 lines>...
            return sn.assert_found(r'Hello, World\!', self.stdout)
  File "/path/to/reframe/unittests/resources/checks/hellocheck.py", line 26, in HelloTest
    p = parameter(config_parameterization(valid_systems, valid_prog_environs))
  File "/path/to/reframe/reframe/core/parameters.py", line 156, in __init__
    self.values = tuple(values)
                  ~~~~~^^^^^^^^
  File "/path/to/reframe/unittests/resources/checks/hellocheck.py", line 13, in config_parameterization
    for sys, envs in valid_sysenv_comb(valid_systems, valid_prog_environs).items():
                     ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/path/to/reframe/reframe/core/runtime.py", line 397, in valid_sysenv_comb
    curr_sys = runtime().system
               ~~~~~~~^^
  File "/path/to/reframe/reframe/core/runtime.py", line 215, in runtime
    raise ReframeFatalError('no runtime context is configured')
reframe.core.exceptions.ReframeFatalError: no runtime context is configured

The reason is that we unconditionally load the Python config file here:

mod = util.import_module_from_file(filename, load_parents=True)

and then search for the site_configuration. As a result, the test module is imported and it tries to load the runtime to get the valid_sysenv_comb() function, but no runtime is defined, because no configuration is loaded.

We should the Python configuration loading more robust by adding a static check first as with the tests.

Metadata

Metadata

Assignees

Type

Projects

Status
Todo

Relationships

None yet

Development

No branches or pull requests

Issue actions