From b488a0a91816055cac78f6dc6a09a1bc90f037e3 Mon Sep 17 00:00:00 2001 From: Alex Ward Date: Tue, 7 Apr 2026 15:16:34 +0100 Subject: [PATCH 1/2] improve ExecutionResult by allowing access to output, inputs, expected_output, and duration Co-Authored-By: Claude --- src/pyeval/_core.py | 16 ++++++++++++++ tests/test_execution_result.py | 38 ++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 tests/test_execution_result.py diff --git a/src/pyeval/_core.py b/src/pyeval/_core.py index d50ffbf..6b96ce5 100644 --- a/src/pyeval/_core.py +++ b/src/pyeval/_core.py @@ -37,6 +37,22 @@ class ExecutionResult: ctx: EvaluatorContext failures: list[EvaluatorFailure] = field(default_factory=list) + @property + def output(self) -> Any: + return self.ctx.output + + @property + def inputs(self) -> Any: + return self.ctx.inputs + + @property + def expected_output(self) -> Any: + return self.ctx.expected_output + + @property + def duration(self) -> float: + 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 From aa7bb3bd20b597e52ca10c2b0bf010efa027ae78 Mon Sep 17 00:00:00 2001 From: Alex Ward Date: Tue, 7 Apr 2026 15:22:18 +0100 Subject: [PATCH 2/2] update docs Co-Authored-By: Claude --- README.md | 2 +- src/pyeval/_core.py | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) 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 6b96ce5..8f78cab 100644 --- a/src/pyeval/_core.py +++ b/src/pyeval/_core.py @@ -34,23 +34,39 @@ @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: