Source code for reframe.core.decorators

#
# Decorators for registering tests with the framework
#

__all__ = ['parameterized_test', 'simple_test', 'required_version']


import collections
import inspect

import reframe
from reframe.core.exceptions import ReframeSyntaxError
from reframe.core.logging import getlogger
from reframe.core.pipeline import RegressionTest
from reframe.utility.versioning import Version, VersionValidator


def _register_test(cls, args=None):
    def _instantiate():
        ret = []
        for cls, args in mod.__rfm_test_registry:
            try:
                if cls in mod.__rfm_skip_tests:
                    continue

            except AttributeError:
                mod.__rfm_skip_tests = set()

            if isinstance(args, collections.Sequence):
                ret.append(cls(*args))
            elif isinstance(args, collections.Mapping):
                ret.append(cls(**args))
            elif args is None:
                ret.append(cls())

        return ret

    mod = inspect.getmodule(cls)
    if not hasattr(mod, '_rfm_gettests'):
        mod._rfm_gettests = _instantiate

    try:
        mod.__rfm_test_registry.append((cls, args))
    except AttributeError:
        mod.__rfm_test_registry = [(cls, args)]


def _validate_test(cls):
    if not issubclass(cls, RegressionTest):
        raise ReframeSyntaxError('the decorated class must be a '
                                 'subclass of RegressionTest')


[docs]def simple_test(cls): """Class decorator for registering parameterless tests with ReFrame. The decorated class must derive from :class:`reframe.core.pipeline.RegressionTest`. This decorator is also available directly under the :mod:`reframe` module. .. versionadded:: 2.13 """ _validate_test(cls) _register_test(cls) return cls
[docs]def parameterized_test(*inst): """Class decorator for registering multiple instantiations of a test class. The decorated class must derive from :class:`reframe.core.pipeline.RegressionTest`. This decorator is also available directly under the :mod:`reframe` module. :arg inst: The different instantiations of the test. Each instantiation argument may be either a sequence or a mapping. .. versionadded:: 2.13 .. note:: This decorator does not instantiate any test. It only registers them. The actual instantiation happens during the loading phase of the test. """ def _do_register(cls): _validate_test(cls) for args in inst: _register_test(cls, args) return cls return _do_register
[docs]def required_version(*versions): """Class decorator for specifying the required ReFrame versions for the following test. If the test is not compatible with the current ReFrame version it will be skipped. :arg versions: A list of ReFrame version specifications that this test is allowed to run. A version specification string can have one of the following formats: 1. ``VERSION``: Specifies a single version. 2. ``{OP}VERSION``, where ``{OP}`` can be any of ``>``, ``>=``, ``<``, ``<=``, ``==`` and ``!=``. For example, the version specification string ``'>=2.15'`` will only allow the following test to be loaded only by ReFrame 2.15 and higher. The ``==VERSION`` specification is the equivalent of ``VERSION``. 3. ``V1..V2``: Specifies a range of versions. You can specify multiple versions with this decorator, such as ``@required_version('2.13', '>=2.16')``, in which case the test will be selected if *any* of the versions is satisfied, even if the versions specifications are conflicting. .. versionadded:: 2.13 """ if not versions: raise ValueError('no versions specified') conditions = [VersionValidator(v) for v in versions] def _skip_tests(cls): mod = inspect.getmodule(cls) if not hasattr(mod, '__rfm_skip_tests'): mod.__rfm_skip_tests = set() if not any(c.validate(reframe.VERSION) for c in conditions): getlogger().info('skipping incompatible test defined' ' in class: %s' % cls.__name__) mod.__rfm_skip_tests.add(cls) return cls return _skip_tests