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)
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)
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)
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)