diff --git a/README.md b/README.md index 22eeafc..f0c9eb8 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ using a familiar Arrange, Act, Evaluate pattern. ## Example ```python -from pyeval import dataset, Case, EqualsExpected, Contains +from pyeval import dataset, execute, Case, EqualsExpected, Contains def uppercase_text(text: str) -> str: diff --git a/src/pyeval/_core.py b/src/pyeval/_core.py index d50ffbf..8f78cab 100644 --- a/src/pyeval/_core.py +++ b/src/pyeval/_core.py @@ -34,9 +34,41 @@ @dataclass class ExecutionResult: + """The result of running a task via :func:`execute`. + + Provides direct access to the task's output and the case inputs for use + in assertions or additional evaluations:: + + result = execute(my_func, case) + + assert "expected substring" in result.output + + result.evaluate(EqualsExpected()) + """ + ctx: EvaluatorContext failures: list[EvaluatorFailure] = field(default_factory=list) + @property + def output(self) -> Any: + """The value returned by the task function.""" + return self.ctx.output + + @property + def inputs(self) -> Any: + """The inputs passed to the task function, taken from the case.""" + return self.ctx.inputs + + @property + def expected_output(self) -> Any: + """The expected output from the case, or ``None`` if not set.""" + return self.ctx.expected_output + + @property + def duration(self) -> float: + """How long the task took to run, in seconds.""" + return self.ctx.duration + def evaluate(self, evaluator: Evaluator) -> None: results = _CURRENT_EVAL_RESULTS.get() if results is None: diff --git a/tests/test_execution_result.py b/tests/test_execution_result.py new file mode 100644 index 0000000..9718c81 --- /dev/null +++ b/tests/test_execution_result.py @@ -0,0 +1,38 @@ +from pydantic_evals import Case + +from pyeval import execute + + +def _identity(x): + return x + + +def test_output_returns_task_return_value(): + case = Case(name="test", inputs="hello") + result = execute(_identity, case) + assert result.output == "hello" + + +def test_inputs_returns_case_inputs(): + case = Case(name="test", inputs="hello") + result = execute(_identity, case) + assert result.inputs == "hello" + + +def test_expected_output_returns_case_expected_output(): + case = Case(name="test", inputs="hello", expected_output="world") + result = execute(_identity, case) + assert result.expected_output == "world" + + +def test_expected_output_is_none_when_not_set(): + case = Case(name="test", inputs="hello") + result = execute(_identity, case) + assert result.expected_output is None + + +def test_duration_is_a_float(): + case = Case(name="test", inputs="hello") + result = execute(_identity, case) + assert isinstance(result.duration, float) + assert result.duration > 0