diff --git a/docs/config_reference.rst b/docs/config_reference.rst index 46da7eca51..7629c1a199 100644 --- a/docs/config_reference.rst +++ b/docs/config_reference.rst @@ -416,8 +416,7 @@ System Partition Configuration :required: No :default: ``{}`` - User defined attributes of the system partition that will be accessible from the ReFrame tests. - By default it is an empty dictionary. + User defined attributes of the partition. This will be accessible through the :attr:`~reframe.core.systems.SystemPartition.extras` attribute of the :attr:`~reframe.core.pipeline.RegressionTest.current_partition`. .. versionadded:: 3.5.0 @@ -582,6 +581,16 @@ They are associated with `system partitions <#system-partition-configuration>`__ Variables are set after the environment modules are loaded. +.. js:attribute:: .environments[].extras + + :required: No + :default: ``{}`` + + User defined attributes of the environment. This will be accessible through the :attr:`~reframe.core.environments.Environment.extras` attribute of the :attr:`~reframe.core.pipeline.RegressionTest.current_environ`. + + .. versionadded:: 3.9.1 + + .. js:attribute:: .environments[].cc :required: No diff --git a/reframe/core/environments.py b/reframe/core/environments.py index aa5aec5377..16331762c3 100644 --- a/reframe/core/environments.py +++ b/reframe/core/environments.py @@ -37,13 +37,14 @@ class Environment(jsonext.JSONSerializable): Users may not create :class:`Environment` objects directly. ''' - def __init__(self, name, modules=None, variables=None): + def __init__(self, name, modules=None, variables=None, extras=None): modules = modules or [] variables = variables or [] self._name = name self._modules = normalize_module_list(modules) self._module_names = [m['name'] for m in self._modules] self._variables = collections.OrderedDict(variables) + self._extras = extras or {} @property def name(self): @@ -89,6 +90,17 @@ def variables(self): ''' return util.MappingView(self._variables) + @property + def extras(self): + '''User defined properties defined in the configuration. + + .. versionadded:: 3.9.1 + + :type: :class:`Dict[str, object]` + ''' + + return self._extras + def __eq__(self, other): if not isinstance(other, type(self)): return NotImplemented @@ -161,6 +173,7 @@ def __init__(self, name, modules=None, variables=None, + extras=None, cc='cc', cxx='CC', ftn='ftn', @@ -171,7 +184,7 @@ def __init__(self, fflags=None, ldflags=None, **kwargs): - super().__init__(name, modules, variables) + super().__init__(name, modules, variables, extras) self._cc = cc self._cxx = cxx self._ftn = ftn diff --git a/reframe/core/systems.py b/reframe/core/systems.py index 2dd22fb3b5..78a75f2488 100644 --- a/reframe/core/systems.py +++ b/reframe/core/systems.py @@ -365,13 +365,11 @@ def devices(self): @property def extras(self): - '''User defined attributes of the system. - - By default, it is an empty dictionary. + '''User defined properties defined in the configuration. .. versionadded:: 3.5.0 - :type: :class:`object` + :type: :class:`Dict[str, object]` ''' return self._extras @@ -481,6 +479,7 @@ def create(cls, site_config): name=e, modules=site_config.get(f'environments/@{e}/modules'), variables=site_config.get(f'environments/@{e}/variables'), + extras=site_config.get(f'environments/@{e}/extras'), cc=site_config.get(f'environments/@{e}/cc'), cxx=site_config.get(f'environments/@{e}/cxx'), ftn=site_config.get(f'environments/@{e}/ftn'), diff --git a/reframe/schemas/config.json b/reframe/schemas/config.json index 75625f8e0d..cc15cc62b7 100644 --- a/reframe/schemas/config.json +++ b/reframe/schemas/config.json @@ -357,6 +357,7 @@ "type": "array", "items": {"type": "string"} }, + "extras": {"type": "object"}, "target_systems": {"$ref": "#/defs/system_ref"} }, "required": ["name"], @@ -494,6 +495,7 @@ "environments/cxxflags": [], "environments/fflags": [], "environments/ldflags": [], + "environments/extras": {}, "environments/target_systems": ["*"], "general/check_search_path": ["${RFM_INSTALL_PREFIX}/checks/"], "general/check_search_recursive": false, diff --git a/unittests/resources/settings.py b/unittests/resources/settings.py index d585a6b2c8..a32ce53429 100644 --- a/unittests/resources/settings.py +++ b/unittests/resources/settings.py @@ -163,6 +163,10 @@ 'modules': [ {'name': 'PrgEnv-gnu', 'collection': False, 'path': None} ], + 'extras': { + 'foo': 2, + 'bar': 'y' + }, }, { 'name': 'PrgEnv-gnu', @@ -170,6 +174,10 @@ 'cc': 'gcc', 'cxx': 'g++', 'ftn': 'gfortran', + 'extras': { + 'foo': 1, + 'bar': 'x' + }, 'target_systems': ['testsys:login'] }, { diff --git a/unittests/test_config.py b/unittests/test_config.py index d35f6e2891..a03692ef41 100644 --- a/unittests/test_config.py +++ b/unittests/test_config.py @@ -259,6 +259,10 @@ def test_select_subconfig(): assert site_config.get('environments/1/cxx') == 'CC' assert (site_config.get('environments/@PrgEnv-cray/modules') == [{'name': 'PrgEnv-cray', 'collection': False, 'path': None}]) + assert site_config.get('environments/@PrgEnv-gnu/extras') == {'foo': 1, + 'bar': 'x'} + assert site_config.get('environments/@PrgEnv-cray/extras') == {} + assert len(site_config.get('general')) == 1 assert site_config.get('general/0/check_search_path') == ['a:b'] @@ -358,6 +362,7 @@ def test_system_create(): assert len(partition.environs) == 2 assert partition.environment('PrgEnv-gnu').cc == 'cc' assert partition.environment('PrgEnv-gnu').cflags == [] + assert partition.environment('PrgEnv-gnu').extras == {'foo': 2, 'bar': 'y'} # Check resource instantiation resource_spec = partition.get_resource('gpu', num_gpus_per_node=16) diff --git a/unittests/test_environments.py b/unittests/test_environments.py index ced2013e88..663e91144a 100644 --- a/unittests/test_environments.py +++ b/unittests/test_environments.py @@ -52,7 +52,8 @@ def user_runtime(make_exec_ctx_g): def env0(): return env.Environment( 'TestEnv1', ['testmod_foo'], - [('_var0', 'val1'), ('_var2', '$_var0'), ('_var3', '${_var1}')] + [('_var0', 'val1'), ('_var2', '$_var0'), ('_var3', '${_var1}')], + {'foo': 1, 'bar': 2} ) @@ -74,8 +75,22 @@ def test_env_construction(base_environ, env0): assert env0.variables['_var0'] == 'val1' # No variable expansion, if environment is not loaded - env0.variables['_var2'] == '$_var0' - env0.variables['_var3'] == '${_var1}' + assert env0.variables['_var2'] == '$_var0' + assert env0.variables['_var3'] == '${_var1}' + + # Assert extras + assert env0.extras == {'foo': 1, 'bar': 2} + + +def test_progenv_construction(): + environ = env.ProgEnvironment('myenv', + modules=['modfoo'], + variables=[('var', 'val')], + extras={'foo': 'bar'}) + assert environ.name == 'myenv' + assert environ.modules == ['modfoo'] + assert environ.variables == {'var': 'val'} + assert environ.extras == {'foo': 'bar'} def test_env_snapshot(base_environ, env0, env1):