From d8ee55be2e04e194b6b107299c0ba6156c77b51f Mon Sep 17 00:00:00 2001 From: Vasileios Karakasis Date: Mon, 31 Jan 2022 22:48:27 +0100 Subject: [PATCH 1/2] Add convenience function to check if a test variables is defined --- docs/regression_test_api.rst | 13 +++++++++++++ reframe/core/meta.py | 27 ++++++++++++++++++++++----- unittests/test_variables.py | 3 +++ 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/docs/regression_test_api.rst b/docs/regression_test_api.rst index 4e62e14c3a..19a354e99f 100644 --- a/docs/regression_test_api.rst +++ b/docs/regression_test_api.rst @@ -670,6 +670,19 @@ Therefore, classes that derive from the base :class:`~reframe.core.pipeline.Regr .. automethod:: reframe.core.pipeline.RegressionMixin.variant_name +--------------------- +Class-level utilities +--------------------- + +.. versionadded:: 3.10.1 + + +The :class:`~reframe.core.pipeline.RegressionMixin` and the provides various utilities methods that give access the metadata related to the test class. +This is usually useful when you need to inspect test class properties, such as the parameter or variable space of the test. + +.. automethod:: reframe.core.pipeline.RegressionMixin.is_abstract + +.. automethod:: reframe.core.pipeline.RegressionMixin.is_var_defined ------------------------ Environments and Systems diff --git a/reframe/core/meta.py b/reframe/core/meta.py index 642c4dc4e6..9690bea6a1 100644 --- a/reframe/core/meta.py +++ b/reframe/core/meta.py @@ -829,16 +829,31 @@ def fixture_space(cls): '''Expose the fixture space.''' return cls._rfm_fixture_space + def is_var_defined(cls, name): + '''Check if variable ``name`` is defined. + + A variable is undefined if it is declared and required and no value is + yet assigned to it. + + :param name: The name of the variable to check if it is defined. + :returns: :obj:`True` if the variable is defined, :obj:`False` otherwise. + + .. versionadded:: 3.10.1 + ''' + try: + return cls.var_space[name].is_defined() + except KeyError: + raise ValueError(f'no such variable: {name!r}') + def is_abstract(cls): '''Check if the class is an abstract test. - This is the case when some parameters are undefined, which results in - the length of the parameter space being 0. + A test is considered abstract if any of its direct or indirect + parameters (inherited from a base class or from a fixture) is + undefined. - :return: bool indicating whether the test or any of its fixtures has - undefined parameters. + :returns: :obj:`True` if the test is abstract, :obj:`False` otherwise. - :meta private: ''' return cls.num_variants == 0 @@ -908,6 +923,8 @@ class HelloTest(rfm.RunOnlyRegressionTest): :param kwargs: Any keyword arguments to be passed to the :class:`RegressionTestMeta` metaclass. + .. versionadded:: 3.10.0 + ''' namespace = RegressionTestMeta.__prepare__(name, bases, **kwargs) namespace.update(body) diff --git a/unittests/test_variables.py b/unittests/test_variables.py index 3d755aa99c..4b9e1c5c8c 100644 --- a/unittests/test_variables.py +++ b/unittests/test_variables.py @@ -39,6 +39,9 @@ def test_custom_variable(OneVarTest): assert OneVarTest.foo == 10 assert hasattr(inst, 'foo') assert inst.foo == 10 + assert OneVarTest.is_var_defined('foo') + with pytest.raises(ValueError): + assert OneVarTest.is_var_defined('bar') def test_redeclare_builtin_var_clash(NoVarsTest): From 2d2a80b3cc9ba09658a79e980bc1cc6196c4d609 Mon Sep 17 00:00:00 2001 From: Vasileios Karakasis Date: Tue, 1 Feb 2022 09:46:08 +0100 Subject: [PATCH 2/2] Add set_var_default() convenience method --- docs/regression_test_api.rst | 14 -------------- reframe/core/meta.py | 16 ---------------- reframe/core/pipeline.py | 20 ++++++++++++++++++++ unittests/test_pipeline.py | 18 ++++++++++++++++++ unittests/test_variables.py | 3 --- 5 files changed, 38 insertions(+), 33 deletions(-) diff --git a/docs/regression_test_api.rst b/docs/regression_test_api.rst index 19a354e99f..98c4454737 100644 --- a/docs/regression_test_api.rst +++ b/docs/regression_test_api.rst @@ -670,20 +670,6 @@ Therefore, classes that derive from the base :class:`~reframe.core.pipeline.Regr .. automethod:: reframe.core.pipeline.RegressionMixin.variant_name ---------------------- -Class-level utilities ---------------------- - -.. versionadded:: 3.10.1 - - -The :class:`~reframe.core.pipeline.RegressionMixin` and the provides various utilities methods that give access the metadata related to the test class. -This is usually useful when you need to inspect test class properties, such as the parameter or variable space of the test. - -.. automethod:: reframe.core.pipeline.RegressionMixin.is_abstract - -.. automethod:: reframe.core.pipeline.RegressionMixin.is_var_defined - ------------------------ Environments and Systems ------------------------ diff --git a/reframe/core/meta.py b/reframe/core/meta.py index 9690bea6a1..e03405579e 100644 --- a/reframe/core/meta.py +++ b/reframe/core/meta.py @@ -829,22 +829,6 @@ def fixture_space(cls): '''Expose the fixture space.''' return cls._rfm_fixture_space - def is_var_defined(cls, name): - '''Check if variable ``name`` is defined. - - A variable is undefined if it is declared and required and no value is - yet assigned to it. - - :param name: The name of the variable to check if it is defined. - :returns: :obj:`True` if the variable is defined, :obj:`False` otherwise. - - .. versionadded:: 3.10.1 - ''' - try: - return cls.var_space[name].is_defined() - except KeyError: - raise ValueError(f'no such variable: {name!r}') - def is_abstract(cls): '''Check if the class is an abstract test. diff --git a/reframe/core/pipeline.py b/reframe/core/pipeline.py index aa8b82deb5..83f3d42cb8 100644 --- a/reframe/core/pipeline.py +++ b/reframe/core/pipeline.py @@ -1166,6 +1166,26 @@ def fixture_variant(self): ''' return getattr(self, '_rfm_fixt_variant', None) + def set_var_default(self, name, value): + '''Set the default value of a variable if variable is undefined. + + A variable is undefined if it is declared and required and no value is + yet assigned to it. + + :param name: The name of the variable. + :param value: The value to set the variable to. + :raises ValueError: If the variable does not exist + + .. versionadded:: 3.10.1 + + ''' + var_space = type(self).var_space + if name not in var_space: + raise ValueError(f'no such variable: {name!r}') + + if not var_space[name].is_defined(): + setattr(self, name, value) + @property def perfvalues(self): return util.MappingView(self._perfvalues) diff --git a/unittests/test_pipeline.py b/unittests/test_pipeline.py index d81f42708f..67c78775bc 100644 --- a/unittests/test_pipeline.py +++ b/unittests/test_pipeline.py @@ -1527,6 +1527,24 @@ def validate(self): _run(hello_cls(), *local_exec_ctx) +def test_set_var_default(): + class _X(rfm.RunOnlyRegressionTest): + foo = variable(int, value=10) + bar = variable(int) + + @run_after('init') + def set_defaults(self): + self.set_var_default('foo', 100) + self.set_var_default('bar', 100) + + with pytest.raises(ValueError): + self.set_var_default('foobar', 10) + + x = _X() + assert x.foo == 10 + assert x.bar == 100 + + def test_set_name_deprecation(): from reframe.core.warnings import ReframeDeprecationWarning diff --git a/unittests/test_variables.py b/unittests/test_variables.py index 4b9e1c5c8c..3d755aa99c 100644 --- a/unittests/test_variables.py +++ b/unittests/test_variables.py @@ -39,9 +39,6 @@ def test_custom_variable(OneVarTest): assert OneVarTest.foo == 10 assert hasattr(inst, 'foo') assert inst.foo == 10 - assert OneVarTest.is_var_defined('foo') - with pytest.raises(ValueError): - assert OneVarTest.is_var_defined('bar') def test_redeclare_builtin_var_clash(NoVarsTest):