# Copyright French Alternative Energies and Atomic Energy Commission
# Contributors: valjean developers
# valjean-support@cea.fr
#
# This software is a computer program whose purpose is to analyze and
# post-process numerical simulation results.
#
# This software is governed by the CeCILL license under French law and abiding
# by the rules of distribution of free software. You can use, modify and/ or
# redistribute the software under the terms of the CeCILL license as circulated
# by CEA, CNRS and INRIA at the following URL: http://www.cecill.info.
#
# As a counterpart to the access to the source code and rights to copy, modify
# and redistribute granted by the license, users are provided only with a
# limited warranty and the software's author, the holder of the economic
# rights, and the successive licensors have only limited liability.
#
# In this respect, the user's attention is drawn to the risks associated with
# loading, using, modifying and/or developing or reproducing the software by
# the user in light of its specific status of free software, that may mean that
# it is complicated to manipulate, and that also therefore means that it is
# reserved for developers and experienced professionals having in-depth
# computer knowledge. Users are therefore encouraged to load and test the
# software's suitability as regards their requirements in conditions enabling
# the security of their systems and/or data to be ensured and, more generally,
# to use and operate it in the same conditions as regards security.
#
# The fact that you are presently reading this means that you have had
# knowledge of the CeCILL license and that you accept its terms.
'''The purpose of this module is to define the :class:`EvalTestTask` class, a
task that evaluates a collection of :class:`~.gavroche.test.Test` objects and
transforms them into :class:`~.gavroche.test.TestResult` objects, which can be
subsequently processed for inclusion in a test report.
'''
import logging
from pathlib import Path
from ..path import ensure, sanitize_filename
from ..cosette.task import TaskStatus
from ..cosette.use import from_env
from ..cosette.pythontask import PythonTask
from ..gavroche.test import Test, TestResultFailed
LOGGER = logging.getLogger(__name__)
[docs]
def actually_eval_test(test):
'''Actually perform test evaluation.
:returns: the result of test evaluation.
:rtype: TestResult
:raises TestResultFailed: if the underlying test raises any exception.
'''
try:
res = test.evaluate()
except Exception as ex: # pylint: disable=broad-except
LOGGER.error('The test failed with error: \n%s', ex)
return TestResultFailed(test, ex)
return res
[docs]
class EvalTestTask(PythonTask):
'''Class that evaluates a list of tests and stores the resulting
:class:`~.TestResult` objects in the environment.'''
[docs]
@classmethod
def from_test_task(cls, test_task, name=None):
'''This method instantiates an :class:`EvalTestTask` that will evaluate
all the tests generated by a given task.
:param Task test_task: a task that is expected to generate a list of
tests as a result.
'''
test_task_name = test_task.name
if name is None:
eval_task_name = test_task_name + '.eval'
else:
eval_task_name = name
return cls(eval_task_name, test_task_name, deps=[test_task])
[docs]
def __init__(self, name, test_task_name, *, deps=None, soft_deps=None):
'''Direct instantiation of an :class:`EvalTestTask`.
:param str name: the name of this task.
:param str test_task_name: the name of the task that generated the
tests.
:param deps: the list of dependencies for this task.
:type deps: list(Task) or None
:param soft_deps: the list of soft dependencies for this task.
:type soft_deps: list(Task) or None
'''
def evaluate(*, env, config):
tests = from_env(env=env, task_name=test_task_name, key='result')
if not isinstance(tests, list):
raise TypeError('Expected a list of tests in EvalTestTask '
f'{self.name!r}; got a {type(tests)} instead')
for test in tests:
if not isinstance(test, Test):
raise TypeError('Expected a list of tests in EvalTestTask '
f'{self.name!r}, but one of the list '
'elements is a {type(test)}')
results = [actually_eval_test(test) for test in tests]
output_dir = Path(config.query('path', 'output-root'),
sanitize_filename(self.name))
ensure(output_dir, is_dir=True)
env_up = {self.name: {'result': results,
'output_dir': str(output_dir)}}
status = TaskStatus.DONE
return env_up, status
super().__init__(name, evaluate, deps=deps, soft_deps=soft_deps,
env_kwarg='env', config_kwarg='config')
[docs]
def evaluate_tests(test_fn, name=None):
'''Create an :class:`EvalTestTask` objects for the given test.
:param test_fn: a function that produces tests, wrapped in a
:class:`~valjean.cosette.use.Use` decorator.
:type test_fn: valjean.cosette.use.Use
:param str name: the name of the :class:`EvalTestTask` object.
:returns: the task that evaluates your tests.
:rtype: EvalTestTask
'''
return EvalTestTask.from_test_task(test_fn.get_task(), name=name)