Skip to content

Commit 285d22f

Browse files
author
Vasileios Karakasis
authored
Merge pull request #2046 from ekouts/feat/required_version
[feat] Make the `@required_version` decorator a class definition parameter
2 parents 3978cc5 + 13a171b commit 285d22f

File tree

3 files changed

+80
-20
lines changed

3 files changed

+80
-20
lines changed

reframe/core/decorators.py

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,17 @@ def _validate_test(cls):
9191
raise ValueError(f'decorated test ({cls.__qualname__!r}) has one or '
9292
f'more undefined parameters')
9393

94+
conditions = [VersionValidator(v) for v in cls._rfm_required_version]
95+
if (cls._rfm_required_version and
96+
not any(c.validate(osext.reframe_version()) for c in conditions)):
97+
98+
getlogger().warning(f"skipping incompatible test "
99+
f"'{cls.__qualname__}': not valid for ReFrame "
100+
f"version {osext.reframe_version().split('-')[0]}")
101+
return False
102+
103+
return True
104+
94105

95106
def simple_test(cls):
96107
'''Class decorator for registering tests with ReFrame.
@@ -101,10 +112,9 @@ def simple_test(cls):
101112
102113
.. versionadded:: 2.13
103114
'''
104-
_validate_test(cls)
105-
106-
for _ in cls.param_space:
107-
_register_test(cls)
115+
if _validate_test(cls):
116+
for _ in cls.param_space:
117+
_register_test(cls)
108118

109119
return cls
110120

@@ -139,14 +149,14 @@ def parameterized_test(*inst):
139149
)
140150

141151
def _do_register(cls):
142-
_validate_test(cls)
143-
if not cls.param_space.is_empty():
144-
raise ValueError(
145-
f'{cls.__qualname__!r} is already a parameterized test'
146-
)
152+
if _validate_test(cls):
153+
if not cls.param_space.is_empty():
154+
raise ValueError(
155+
f'{cls.__qualname__!r} is already a parameterized test'
156+
)
147157

148-
for args in inst:
149-
_register_test(cls, args)
158+
for args in inst:
159+
_register_test(cls, args)
150160

151161
return cls
152162

@@ -187,6 +197,12 @@ def required_version(*versions):
187197
These should be written as ``3.5.0`` and ``3.5.0-dev.0``.
188198
189199
'''
200+
warn.user_deprecation_warning(
201+
"the '@required_version' decorator is deprecated; please set "
202+
"the 'require_version' parameter in the class definition instead",
203+
from_version='3.7.0'
204+
)
205+
190206
if not versions:
191207
raise ValueError('no versions specified')
192208

@@ -198,8 +214,10 @@ def _skip_tests(cls):
198214
mod.__rfm_skip_tests = set()
199215

200216
if not any(c.validate(osext.reframe_version()) for c in conditions):
201-
getlogger().info('skipping incompatible test defined'
202-
' in class: %s' % cls.__name__)
217+
getlogger().warning(
218+
f"skipping incompatible test '{cls.__qualname__}': not valid "
219+
f"for ReFrame version {osext.reframe_version().split('-')[0]}"
220+
)
203221
mod.__rfm_skip_tests.add(cls)
204222

205223
return cls

reframe/core/pipeline.py

Lines changed: 45 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,14 +138,49 @@ class RegressionTest(RegressionMixin, jsonext.JSONSerializable):
138138
This class provides the implementation of the pipeline phases that the
139139
regression test goes through during its lifetime.
140140
141-
.. warning::
142-
.. versionchanged:: 3.4.2
143-
Multiple inheritance with a shared common ancestor is not allowed.
141+
This class accepts parameters at the *class definition*, i.e., the test
142+
class can be defined as follows:
143+
144+
.. code-block:: python
145+
146+
class MyTest(RegressionTest, param='foo', ...):
147+
148+
where ``param`` is one of the following:
149+
150+
:param pin_prefix: lock the test prefix to the directory where the current
151+
class lives.
152+
153+
:param require_version: a list of ReFrame version specifications that this
154+
test is allowed to run. A version specification string can have one of
155+
the following formats:
156+
157+
- ``VERSION``: Specifies a single version.
158+
- ``{OP}VERSION``, where ``{OP}`` can be any of ``>``, ``>=``, ``<``,
159+
``<=``, ``==`` and ``!=``. For example, the version specification
160+
string ``'>=3.5.0'`` will allow the following test to be loaded
161+
only by ReFrame 3.5.0 and higher. The ``==VERSION`` specification
162+
is the equivalent of ``VERSION``.
163+
- ``V1..V2``: Specifies a range of versions.
164+
165+
The test will be selected if *any* of the versions is satisfied, even
166+
if the versions specifications are conflicting.
167+
168+
:param special: allow pipeline stage methods to be overriden in this class.
144169
145170
.. note::
146171
.. versionchanged:: 2.19
147172
Base constructor takes no arguments.
148173
174+
.. versionadded:: 3.3
175+
The ``pin_prefix`` class definition parameter is added.
176+
177+
.. versionadded:: 3.7.0
178+
The ``require_verion`` class definition parameter is added.
179+
180+
.. warning::
181+
.. versionchanged:: 3.4.2
182+
Multiple inheritance with a shared common ancestor is not allowed.
183+
149184
'''
150185

151186
def disable_hook(self, hook_name):
@@ -805,10 +840,16 @@ def __getattribute__(self, name):
805840
return super().__getattribute__(name)
806841

807842
@classmethod
808-
def __init_subclass__(cls, *, special=False, pin_prefix=False, **kwargs):
843+
def __init_subclass__(cls, *, special=False, pin_prefix=False,
844+
require_version=None, **kwargs):
809845
super().__init_subclass__(**kwargs)
810846
cls._rfm_override_final = special
811847

848+
if require_version:
849+
cls._rfm_required_version = require_version
850+
elif not hasattr(cls, '_rfm_required_version'):
851+
cls._rfm_required_version = []
852+
812853
# Insert the prefix to pin the test to if the test lives in a test
813854
# library with resources in it.
814855
if pin_prefix:

unittests/test_loader.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,10 @@ def test_load_error(loader):
6161

6262

6363
def test_load_bad_required_version(loader):
64-
with pytest.raises(ValueError):
65-
loader.load_from_file('unittests/resources/checks_unlisted/'
66-
'no_required_version.py')
64+
with pytest.warns(ReframeDeprecationWarning):
65+
with pytest.raises(ValueError):
66+
loader.load_from_file('unittests/resources/checks_unlisted/'
67+
'no_required_version.py')
6768

6869

6970
def test_load_bad_init(loader):

0 commit comments

Comments
 (0)