示例#1
0
文件: meta.py 项目: toxa81/reframe
    def __prepare__(metacls, name, bases, **kwargs):
        namespace = super().__prepare__(name, bases, **kwargs)

        # Regression test parameter space defined at the class level
        local_param_space = namespaces.LocalNamespace()
        namespace['_rfm_local_param_space'] = local_param_space

        # Directive to insert a regression test parameter directly in the
        # class body as: `P0 = parameter([0,1,2,3])`.
        namespace['parameter'] = parameters.TestParam

        # Regression test var space defined at the class level
        local_var_space = namespaces.LocalNamespace()
        namespace['_rfm_local_var_space'] = local_var_space

        # Directives to add/modify a regression test variable
        namespace['variable'] = variables.TestVar
        namespace['required'] = variables.UndefineVar()
        return metacls.MetaNamespace(namespace)
示例#2
0
    def __prepare__(metacls, name, bases, **kwargs):
        namespace = super().__prepare__(name, bases, **kwargs)

        # Keep reference to the bases inside the namespace
        namespace['_rfm_bases'] = [
            b for b in bases if hasattr(b, '_rfm_var_space')
        ]

        # Regression test parameter space defined at the class level
        local_param_space = namespaces.LocalNamespace()
        namespace['_rfm_local_param_space'] = local_param_space

        # Directive to insert a regression test parameter directly in the
        # class body as: `P0 = parameter([0,1,2,3])`.
        namespace['parameter'] = parameters.TestParam

        # Regression test var space defined at the class level
        local_var_space = namespaces.LocalNamespace()
        namespace['_rfm_local_var_space'] = local_var_space

        # Directives to add/modify a regression test variable
        namespace['variable'] = variables.TestVar
        namespace['required'] = variables.Undefined

        # Utility decorators
        namespace['_rfm_ext_bound'] = set()

        def bind(fn, name=None):
            '''Directive to bind a free function to a class.

            See online docs for more information.

            .. note::
               Functions bound using this directive must be re-inspected after
               the class body execution has completed. This directive attaches
               the external method into the class namespace and returns the
               associated instance of the :class:`WrappedFunction`. However,
               this instance may be further modified by other ReFrame builtins
               such as :func:`run_before`, :func:`run_after`, :func:`final` and
               so on after it was added to the namespace, which would bypass
               the logic implemented in the :func:`__setitem__` method from the
               :class:`MetaNamespace` class. Hence, we track the items set by
               this directive in the ``_rfm_ext_bound`` set, so they can be
               later re-inspected.
            '''

            inst = metacls.WrappedFunction(fn, name)
            namespace[inst.__name__] = inst

            # Track the imported external functions
            namespace['_rfm_ext_bound'].add(inst.__name__)
            return inst

        def final(fn):
            '''Indicate that a function is final and cannot be overridden.'''

            fn._rfm_final = True
            return fn

        namespace['bind'] = bind
        namespace['final'] = final
        namespace['_rfm_final_methods'] = set()

        # Hook-related functionality
        def run_before(stage):
            '''Decorator for attaching a test method to a given stage.

            See online docs for more information.
            '''
            return hooks.attach_to('pre_' + stage)

        def run_after(stage):
            '''Decorator for attaching a test method to a given stage.

            See online docs for more information.
            '''
            return hooks.attach_to('post_' + stage)

        namespace['run_before'] = run_before
        namespace['run_after'] = run_after
        namespace['require_deps'] = hooks.require_deps
        namespace['_rfm_hook_registry'] = hooks.HookRegistry()

        # Machinery to add a sanity function
        def sanity_function(fn):
            '''Mark a function as the test's sanity function.

            Decorated functions must be unary and they will be converted into
            deferred expressions.
            '''

            _def_fn = deferrable(fn)
            setattr(_def_fn, '_rfm_sanity_fn', True)
            return _def_fn

        namespace['sanity_function'] = sanity_function
        namespace['deferrable'] = deferrable

        # Machinery to add performance functions
        def performance_function(units, *, perf_key=None):
            '''Decorate a function to extract a performance variable.

            The ``units`` argument indicates the units of the performance
            variable to be extracted.
            The ``perf_key`` optional arg will be used as the name of the
            performance variable. If not provided, the function name will
            be used as the performance variable name.
            '''
            if not isinstance(units, str):
                raise TypeError('performance units must be a string')

            if perf_key and not isinstance(perf_key, str):
                raise TypeError("'perf_key' must be a string")

            def _deco_wrapper(func):
                if not utils.is_trivially_callable(func, non_def_args=1):
                    raise TypeError(
                        f'performance function {func.__name__!r} has more '
                        f'than one argument without a default value')

                @functools.wraps(func)
                def _perf_fn(*args, **kwargs):
                    return _DeferredPerformanceExpression(
                        func, units, *args, **kwargs)

                _perf_key = perf_key if perf_key else func.__name__
                setattr(_perf_fn, '_rfm_perf_key', _perf_key)
                return _perf_fn

            return _deco_wrapper

        namespace['performance_function'] = performance_function
        namespace['_rfm_perf_fns'] = namespaces.LocalNamespace()
        return metacls.MetaNamespace(namespace)
示例#3
0
    def __prepare__(metacls, name, bases, **kwargs):
        namespace = super().__prepare__(name, bases, **kwargs)

        #
        # Initialize the various class level helper data structures
        #

        # Keep reference to the bases inside the namespace
        namespace['_rfm_bases'] = [
            b for b in bases if hasattr(b, '_rfm_var_space')
        ]

        # Regression test parameter space defined at the class level
        namespace['_rfm_local_param_space'] = namespaces.LocalNamespace()

        # Regression test var space defined at the class level
        namespace['_rfm_local_var_space'] = namespaces.LocalNamespace()

        # Regression test fixture space
        namespace['_rfm_local_fixture_space'] = namespaces.LocalNamespace()

        # Utility decorators
        namespace['_rfm_ext_bound'] = set()

        # Loggable properties
        namespace['_rfm_loggable_props'] = []

        namespace['_rfm_final_methods'] = set()
        namespace['_rfm_hook_registry'] = hooks.HookRegistry()
        namespace['_rfm_local_hook_registry'] = hooks.HookRegistry()
        namespace['_rfm_perf_fns'] = namespaces.LocalNamespace()

        def bind(fn, name=None):
            '''Directive to bind a free function to a class.

            See online docs for more information.

            .. note::
               Functions bound using this directive must be re-inspected after
               the class body execution has completed. This directive attaches
               the external method into the class namespace and returns the
               associated instance of the :class:`WrappedFunction`. However,
               this instance may be further modified by other ReFrame builtins
               such as :func:`run_before`, :func:`run_after`, :func:`final` and
               so on after it was added to the namespace, which would bypass
               the logic implemented in the :func:`__setitem__` method from the
               :class:`MetaNamespace` class. Hence, we track the items set by
               this directive in the ``_rfm_ext_bound`` set, so they can be
               later re-inspected.
            '''

            inst = metacls.WrappedFunction(fn, name)
            namespace[inst.__name__] = inst

            # Track the imported external functions
            namespace['_rfm_ext_bound'].add(inst.__name__)
            return inst

        # Register all builtins
        for name in builtins.__all__:
            namespace[name] = getattr(builtins, name)

        namespace['bind'] = bind
        return metacls.MetaNamespace(namespace)
示例#4
0
    def __prepare__(metacls, name, bases, **kwargs):
        namespace = super().__prepare__(name, bases, **kwargs)

        # Keep reference to the bases inside the namespace
        namespace['_rfm_bases'] = [
            b for b in bases if hasattr(b, '_rfm_var_space')
        ]

        # Regression test parameter space defined at the class level
        local_param_space = namespaces.LocalNamespace()
        namespace['_rfm_local_param_space'] = local_param_space

        # Directive to insert a regression test parameter directly in the
        # class body as: `P0 = parameter([0,1,2,3])`.
        namespace['parameter'] = parameters.TestParam

        # Regression test var space defined at the class level
        local_var_space = namespaces.LocalNamespace()
        namespace['_rfm_local_var_space'] = local_var_space

        # Directives to add/modify a regression test variable
        namespace['variable'] = variables.TestVar
        namespace['required'] = variables.Undefined

        def bind(fn, name=None):
            '''Directive to bind a free function to a class.

            See online docs for more information.
            '''

            inst = metacls.WrappedFunction(fn, name)
            namespace[inst.__name__] = inst
            return inst

        namespace['bind'] = bind

        # Hook-related functionality
        def run_before(stage):
            '''Decorator for attaching a test method to a pipeline stage.

            See online docs for more information.
            '''

            if stage not in _USER_PIPELINE_STAGES:
                raise ValueError(
                    f'invalid pipeline stage specified: {stage!r}')

            if stage == 'init':
                raise ValueError('pre-init hooks are not allowed')

            return hooks.attach_to('pre_' + stage)

        namespace['run_before'] = run_before

        def run_after(stage):
            '''Decorator for attaching a test method to a pipeline stage.

            See online docs for more information.
            '''

            if stage not in _USER_PIPELINE_STAGES:
                raise ValueError(
                    f'invalid pipeline stage specified: {stage!r}')

            # Map user stage names to the actual pipeline functions if needed
            if stage == 'init':
                stage = '__init__'
            elif stage == 'compile':
                stage = 'compile_wait'
            elif stage == 'run':
                stage = 'run_wait'

            return hooks.attach_to('post_' + stage)

        namespace['run_after'] = run_after
        namespace['require_deps'] = hooks.require_deps

        # Machinery to add a sanity function
        def sanity_function(fn):
            '''Mark a function as the test's sanity function.

            Decorated functions must be unary and they will be converted into
            deferred expressions.
            '''

            _def_fn = deferrable(fn)
            setattr(_def_fn, '_rfm_sanity_fn', True)
            return _def_fn

        namespace['sanity_function'] = sanity_function
        namespace['deferrable'] = deferrable
        return metacls.MetaNamespace(namespace)