Skip to content

Commit 681440b

Browse files
author
Vasileios Karakasis
authored
Merge pull request #2515 from vkarak/bugfix/setvar-fixtures
[bugfix] Allow setting fixture variables from the command line
2 parents f9d69c8 + c4f4db3 commit 681440b

File tree

5 files changed

+43
-8
lines changed

5 files changed

+43
-8
lines changed

docs/manpage.rst

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,10 @@ Options controlling ReFrame execution
484484

485485
Set variable ``VAR`` in all tests or optionally only in test ``TEST`` to ``VAL``.
486486

487+
``TEST`` can have the form ``[TEST.][FIXT.]*``, in which case ``VAR`` will be set in fixture ``FIXT`` of ``TEST``.
488+
Note that this syntax is recursive on fixtures, so that a variable can be set in a fixture arbitrarily deep.
489+
``TEST`` prefix refers to the test class name, *not* the test name, but ``FIXT`` refers to the fixture name *inside* the referenced test.
490+
487491
Multiple variables can be set at the same time by passing this option multiple times.
488492
This option *cannot* change arbitrary test attributes, but only test variables declared with the :attr:`~reframe.core.pipeline.RegressionMixin.variable` built-in.
489493
If an attempt is made to change an inexistent variable or a test parameter, a warning will be issued.
@@ -511,8 +515,6 @@ Options controlling ReFrame execution
511515
Conversions to arbitrary objects are also supported.
512516
See :class:`~reframe.utility.typecheck.ConvertibleType` for more details.
513517

514-
The optional ``TEST.`` prefix refers to the test class name, *not* the test name.
515-
516518
Variable assignments passed from the command line happen *before* the test is instantiated and is the exact equivalent of assigning a new value to the variable *at the end* of the test class body.
517519
This has a number of implications that users of this feature should be aware of:
518520

@@ -561,6 +563,10 @@ Options controlling ReFrame execution
561563

562564
Proper handling of boolean variables.
563565

566+
.. versionchanged:: 3.11.1
567+
568+
Allow setting variables in fixtures.
569+
564570

565571
.. option:: --skip-performance-check
566572

reframe/core/meta.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,17 @@ def setvar(cls, name, value):
535535
536536
'''
537537

538+
if '.' in name:
539+
# `name` refers to a fixture variable
540+
fixtname, varname = name.split('.', maxsplit=1)
541+
try:
542+
fixt_space = super().__getattribute__('_rfm_fixture_space')
543+
except AttributeError:
544+
'''Catch early access attempt to the variable space.'''
545+
546+
if fixtname in fixt_space:
547+
return fixt_space[fixtname].cls.setvar(varname, value)
548+
538549
try:
539550
var_space = super().__getattribute__('_rfm_var_space')
540551
if name in var_space:

reframe/core/variables.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -281,7 +281,7 @@ def __getattr__(self, name):
281281
def _check_is_defined(self):
282282
if not self.is_defined():
283283
raise ReframeSyntaxError(
284-
f'variable {self._name} is not assigned a value'
284+
f'variable {self._name!r} is not assigned a value'
285285
)
286286

287287
def __repr__(self):

unittests/resources/checks_unlisted/externalvars.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,33 @@
33
import reframe.utility.typecheck as typ
44

55

6+
class Bacon(rfm.RunOnlyRegressionTest):
7+
bacon = variable(int, value=-1)
8+
executable = 'echo'
9+
sanity_patterns = sn.assert_true(1)
10+
11+
12+
class Eggs(rfm.RunOnlyRegressionTest):
13+
eggs = fixture(Bacon)
14+
executable = 'echo'
15+
sanity_patterns = sn.assert_true(1)
16+
17+
618
@rfm.simple_test
719
class external_x(rfm.RunOnlyRegressionTest):
820
valid_systems = ['*']
921
valid_prog_environs = ['*']
1022
foo = variable(int, value=1)
1123
ham = variable(typ.Bool, value=False)
24+
spam = fixture(Eggs)
1225
executable = 'echo'
1326

1427
@sanity_function
1528
def assert_foo(self):
1629
return sn.all([
1730
sn.assert_eq(self.foo, 3),
18-
sn.assert_true(self.ham)
31+
sn.assert_true(self.ham),
32+
sn.assert_eq(self.spam.eggs.bacon, 10)
1933
])
2034

2135

unittests/test_cli.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -837,13 +837,17 @@ def test_detect_host_topology_file(run_reframe, tmp_path):
837837
def test_external_vars(run_reframe):
838838
returncode, stdout, stderr = run_reframe(
839839
checkpath=['unittests/resources/checks_unlisted/externalvars.py'],
840-
more_options=['-S', 'external_x.foo=3', '-S', 'external_y.foo=2',
841-
'-S', 'foolist=3,4', '-S', 'bar=@none',
840+
more_options=['-S', 'external_x.foo=3',
842841
'-S', 'external_x.ham=true',
843-
'-S', 'external_y.baz=false']
842+
'-S', 'external_x.spam.eggs.bacon=10',
843+
'-S', 'external_y.foo=2',
844+
'-S', 'external_y.baz=false',
845+
'-S', 'foolist=3,4',
846+
'-S', 'bar=@none']
844847
)
848+
assert 'PASSED' in stdout
849+
assert 'Ran 6/6 test case(s)' in stdout
845850
assert 'Traceback' not in stdout
846-
assert 'Ran 2/2 test case(s)' in stdout
847851
assert 'Traceback' not in stderr
848852
assert returncode == 0
849853

0 commit comments

Comments
 (0)