reeval-python 0.14.0__tar.gz → 0.16.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {reeval_python-0.14.0 → reeval_python-0.16.1}/PKG-INFO +49 -4
- {reeval_python-0.14.0 → reeval_python-0.16.1}/README.md +48 -3
- {reeval_python-0.14.0 → reeval_python-0.16.1}/pyproject.toml +1 -1
- {reeval_python-0.14.0 → reeval_python-0.16.1}/src/reeval_python/__init__.py +3 -3
- {reeval_python-0.14.0 → reeval_python-0.16.1}/src/reeval_python/_wire.py +251 -124
- {reeval_python-0.14.0 → reeval_python-0.16.1}/src/reeval_python/aio.py +1 -9
- reeval_python-0.16.1/src/reeval_python/binaries.json +55 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/src/reeval_python/checks.py +8 -1
- {reeval_python-0.14.0 → reeval_python-0.16.1}/src/reeval_python/cli.py +24 -7
- {reeval_python-0.14.0 → reeval_python-0.16.1}/src/reeval_python/context.py +39 -7
- {reeval_python-0.14.0 → reeval_python-0.16.1}/src/reeval_python/declare.py +222 -13
- {reeval_python-0.14.0 → reeval_python-0.16.1}/src/reeval_python/errors.py +1 -1
- {reeval_python-0.14.0 → reeval_python-0.16.1}/src/reeval_python/expect.py +51 -23
- reeval_python-0.16.1/src/reeval_python/options.py +86 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/src/reeval_python/runner.py +8 -4
- {reeval_python-0.14.0 → reeval_python-0.16.1}/src/reeval_python/wire.py +7 -3
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/context/expect-fail.eval.py +1 -1
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/context/expect-fail.sync.eval.py +1 -1
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/context/expect.eval.py +2 -1
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/context/expect.sync.eval.py +2 -1
- reeval_python-0.16.1/tests/context/judge.eval.py +14 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/context/judge.sync.eval.py +3 -3
- reeval_python-0.16.1/tests/declare/best-of.eval.py +24 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/declare/compare-questions.eval.py +10 -3
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/declare/questions-attempts.eval.py +22 -5
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/declare/questions-group.eval.py +8 -3
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/declare/questions-state.eval.py +25 -6
- reeval_python-0.16.1/tests/declare/revision.eval.py +20 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/stdio_host.py +13 -3
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/test_api.py +58 -1
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/test_checks.py +26 -5
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/test_cli.py +18 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/test_conformance_context.py +12 -1
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/test_conformance_declare.py +8 -2
- reeval_python-0.16.1/tests/test_load.py +96 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/test_runner_attempts.py +50 -9
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/test_runner_checks.py +2 -1
- reeval_python-0.16.1/tests/test_runner_json.py +92 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/test_runner_sdk.py +19 -3
- reeval_python-0.16.1/tests/test_source.py +191 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/test_types.py +4 -4
- {reeval_python-0.14.0 → reeval_python-0.16.1}/uv.lock +1 -1
- reeval_python-0.14.0/src/reeval_python/binaries.json +0 -55
- reeval_python-0.14.0/src/reeval_python/options.py +0 -54
- reeval_python-0.14.0/tests/context/judge.eval.py +0 -10
- {reeval_python-0.14.0 → reeval_python-0.16.1}/.gitignore +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/CHANGELOG.md +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/LICENSE +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/package.json +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/src/reeval_python/__main__.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/src/reeval_python/environment.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/src/reeval_python/py.typed +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/src/reeval_python/types.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/context/abort.eval.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/context/abort.sync.eval.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/context/exec-retries.eval.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/context/exec-retries.sync.eval.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/context/exec.eval.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/context/exec.sync.eval.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/context/files.eval.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/context/files.sync.eval.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/context/record.async.eval.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/context/record.eval.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/context/send.eval.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/context/send.sync.eval.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/context/sync-async.async.eval.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/context/sync-async.eval.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/declare/compare-variants.eval.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/declare/each-families.eval.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/declare/egress-cascade.eval.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/declare/environment-extend.eval.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/declare/environment-plugin-marketplace.eval.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/declare/environment-plugins.eval.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/declare/groups-skip-todo.eval.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/declare/tags.eval.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/runner_process.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/test_patterns.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/test_python_wheels.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/test_runner_isolation.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/test_runner_misuse.py +0 -0
- {reeval_python-0.14.0 → reeval_python-0.16.1}/tests/test_runner_stdio.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: reeval-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.16.1
|
|
4
4
|
Summary: Python authoring SDK for reeval (*.eval.py eval files)
|
|
5
5
|
Project-URL: Homepage, https://reeval.ai
|
|
6
6
|
Project-URL: Repository, https://github.com/invertase/reeval
|
|
@@ -73,7 +73,7 @@ from reeval_python import SyncAttemptContext, evaluate, expect
|
|
|
73
73
|
def lands(c: SyncAttemptContext) -> None:
|
|
74
74
|
c.send("Create greet.py that prints hi")
|
|
75
75
|
assert c.exec("test -f greet.py").ok
|
|
76
|
-
expect(c.judge("Does greet.py print hi?")).to_pass()
|
|
76
|
+
expect(c.judge("Does greet.py print hi?", contents=["greet.py"])).to_pass()
|
|
77
77
|
```
|
|
78
78
|
|
|
79
79
|
Plain `assert` is first-class, as in pytest: each one in an eval file is a check in the run
|
|
@@ -83,9 +83,47 @@ as in Python, and is recorded with its message and both sides of a comparison as
|
|
|
83
83
|
(`greet.py exists: assert 1 == 2`). An `AssertionError` the body catches isn't a failed check, so
|
|
84
84
|
a retry loop can assert; one the escaping error carries (each failure in a `TaskGroup`'s
|
|
85
85
|
`ExceptionGroup`, or one an error was raised from or while handling) is. Use typed results (`ExecResult.ok`, `Verdict.passed`, `Turn.text`, …) and `c.file(path)`
|
|
86
|
-
for quick checks. Keep `expect` for reeval matchers (`to_have_file`, `to_succeed`,
|
|
86
|
+
for quick checks. Keep `expect` for reeval matchers (`to_have_file`, `to_succeed`, checks that carry on,
|
|
87
87
|
labels) — Playwright-style.
|
|
88
88
|
|
|
89
|
+
#### Checks carry on; `expect.require` is a gate
|
|
90
|
+
|
|
91
|
+
A failed `expect` is recorded and the body carries on, so every later check and judge still runs;
|
|
92
|
+
the attempt fails when the body ends. `expect.require` raises `ReevalAssertionError` instead, for a
|
|
93
|
+
gate the rest depends on:
|
|
94
|
+
|
|
95
|
+
```python
|
|
96
|
+
c.send("Add a sign-up page")
|
|
97
|
+
expect.require(c.exec("npm run build"), "builds").to_succeed() # stops here if the build fails
|
|
98
|
+
expect(c.exec("npm test"), "tests pass").to_succeed() # recorded, carries on
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
reeval records a failed `expect.require` before the error reaches the body. One the body catches
|
|
102
|
+
still fails the attempt when the body ends, and its error says the eval caught it. A plain
|
|
103
|
+
`assert` the body catches records nothing, as in Python.
|
|
104
|
+
|
|
105
|
+
| The body catches | Recorded | Fails the attempt |
|
|
106
|
+
|---|---|---|
|
|
107
|
+
| a failed `expect.require(…)` | a failed check | yes, when the body ends |
|
|
108
|
+
| a failed `assert` | nothing | no |
|
|
109
|
+
| neither (it escapes) | a failed check | yes |
|
|
110
|
+
|
|
111
|
+
So retry with `expect.poll`, which retries the matcher and records only its final outcome, or with
|
|
112
|
+
a plain `assert` or `if` in the loop, never `expect.require` in `try`/`except`:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
# Retries the command until it succeeds, for up to 10 seconds: one check.
|
|
116
|
+
expect.poll(lambda: c.exec("curl -sf localhost:3000"), timeout=10).to_succeed()
|
|
117
|
+
|
|
118
|
+
# A plain assert in a retry loop: only the try that held is recorded.
|
|
119
|
+
for _ in range(3):
|
|
120
|
+
try:
|
|
121
|
+
assert c.exec("test -f ready.txt").ok
|
|
122
|
+
break
|
|
123
|
+
except AssertionError:
|
|
124
|
+
time.sleep(1)
|
|
125
|
+
```
|
|
126
|
+
|
|
89
127
|
Matchers that take a pattern (`to_have_file`, `to_have_run`, `to_have_searched`, `to_have_fetched`,
|
|
90
128
|
`to_have_called_tool`, `to_have_edited`, `to_have_changed`) take a `str` or a compiled `re.Pattern`,
|
|
91
129
|
`str` or `bytes`, with any flags. Python matches it with `pattern.search`, so anything `re` accepts
|
|
@@ -101,12 +139,19 @@ Use snake_case on the context (`read_file`, `write_file`, `file`) and on matcher
|
|
|
101
139
|
`to_pass`, `to_equal`, `to_contain`, …). Matcher failures raise `ReevalAssertionError`.
|
|
102
140
|
|
|
103
141
|
Options are typed (`EvalOptions`, and `JudgeOptions` for `c.judge(…)`), so pyright refuses a
|
|
104
|
-
|
|
142
|
+
misspelled key such as `runz`. They take reeval's keys in snake_case at any depth (`min_lift`,
|
|
105
143
|
`delay_ms`); the keys of `env`, `headers` and the other maps of your own keep their spelling. Every
|
|
106
144
|
duration is seconds or a `timedelta`: `{"timeout": 90}`, `docker(start_timeout=timedelta(minutes=2))`,
|
|
107
145
|
`expect.poll(…, timeout=10)`. `docker()`, `fake_harness()`, `fake_judge()` and `plugin.*` return
|
|
108
146
|
values to pass as options, not data to edit.
|
|
109
147
|
|
|
148
|
+
`c.judge` takes the inputs the judge reads as keywords, and needs at least one: `diff=True`,
|
|
149
|
+
`contents=["src/**"]`, `output=True` with `on=result`, and so on. With none it raises `TypeError`.
|
|
150
|
+
|
|
151
|
+
```python
|
|
152
|
+
expect(c.judge("Is it valid JSON?", on=result, output=True)).to_pass()
|
|
153
|
+
```
|
|
154
|
+
|
|
110
155
|
### `def` and `async def` bodies
|
|
111
156
|
|
|
112
157
|
A `def` body gets a blocking context: `c.exec(…)` runs the command and returns its `ExecResult`,
|
|
@@ -49,7 +49,7 @@ from reeval_python import SyncAttemptContext, evaluate, expect
|
|
|
49
49
|
def lands(c: SyncAttemptContext) -> None:
|
|
50
50
|
c.send("Create greet.py that prints hi")
|
|
51
51
|
assert c.exec("test -f greet.py").ok
|
|
52
|
-
expect(c.judge("Does greet.py print hi?")).to_pass()
|
|
52
|
+
expect(c.judge("Does greet.py print hi?", contents=["greet.py"])).to_pass()
|
|
53
53
|
```
|
|
54
54
|
|
|
55
55
|
Plain `assert` is first-class, as in pytest: each one in an eval file is a check in the run
|
|
@@ -59,9 +59,47 @@ as in Python, and is recorded with its message and both sides of a comparison as
|
|
|
59
59
|
(`greet.py exists: assert 1 == 2`). An `AssertionError` the body catches isn't a failed check, so
|
|
60
60
|
a retry loop can assert; one the escaping error carries (each failure in a `TaskGroup`'s
|
|
61
61
|
`ExceptionGroup`, or one an error was raised from or while handling) is. Use typed results (`ExecResult.ok`, `Verdict.passed`, `Turn.text`, …) and `c.file(path)`
|
|
62
|
-
for quick checks. Keep `expect` for reeval matchers (`to_have_file`, `to_succeed`,
|
|
62
|
+
for quick checks. Keep `expect` for reeval matchers (`to_have_file`, `to_succeed`, checks that carry on,
|
|
63
63
|
labels) — Playwright-style.
|
|
64
64
|
|
|
65
|
+
#### Checks carry on; `expect.require` is a gate
|
|
66
|
+
|
|
67
|
+
A failed `expect` is recorded and the body carries on, so every later check and judge still runs;
|
|
68
|
+
the attempt fails when the body ends. `expect.require` raises `ReevalAssertionError` instead, for a
|
|
69
|
+
gate the rest depends on:
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
c.send("Add a sign-up page")
|
|
73
|
+
expect.require(c.exec("npm run build"), "builds").to_succeed() # stops here if the build fails
|
|
74
|
+
expect(c.exec("npm test"), "tests pass").to_succeed() # recorded, carries on
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
reeval records a failed `expect.require` before the error reaches the body. One the body catches
|
|
78
|
+
still fails the attempt when the body ends, and its error says the eval caught it. A plain
|
|
79
|
+
`assert` the body catches records nothing, as in Python.
|
|
80
|
+
|
|
81
|
+
| The body catches | Recorded | Fails the attempt |
|
|
82
|
+
|---|---|---|
|
|
83
|
+
| a failed `expect.require(…)` | a failed check | yes, when the body ends |
|
|
84
|
+
| a failed `assert` | nothing | no |
|
|
85
|
+
| neither (it escapes) | a failed check | yes |
|
|
86
|
+
|
|
87
|
+
So retry with `expect.poll`, which retries the matcher and records only its final outcome, or with
|
|
88
|
+
a plain `assert` or `if` in the loop, never `expect.require` in `try`/`except`:
|
|
89
|
+
|
|
90
|
+
```python
|
|
91
|
+
# Retries the command until it succeeds, for up to 10 seconds: one check.
|
|
92
|
+
expect.poll(lambda: c.exec("curl -sf localhost:3000"), timeout=10).to_succeed()
|
|
93
|
+
|
|
94
|
+
# A plain assert in a retry loop: only the try that held is recorded.
|
|
95
|
+
for _ in range(3):
|
|
96
|
+
try:
|
|
97
|
+
assert c.exec("test -f ready.txt").ok
|
|
98
|
+
break
|
|
99
|
+
except AssertionError:
|
|
100
|
+
time.sleep(1)
|
|
101
|
+
```
|
|
102
|
+
|
|
65
103
|
Matchers that take a pattern (`to_have_file`, `to_have_run`, `to_have_searched`, `to_have_fetched`,
|
|
66
104
|
`to_have_called_tool`, `to_have_edited`, `to_have_changed`) take a `str` or a compiled `re.Pattern`,
|
|
67
105
|
`str` or `bytes`, with any flags. Python matches it with `pattern.search`, so anything `re` accepts
|
|
@@ -77,12 +115,19 @@ Use snake_case on the context (`read_file`, `write_file`, `file`) and on matcher
|
|
|
77
115
|
`to_pass`, `to_equal`, `to_contain`, …). Matcher failures raise `ReevalAssertionError`.
|
|
78
116
|
|
|
79
117
|
Options are typed (`EvalOptions`, and `JudgeOptions` for `c.judge(…)`), so pyright refuses a
|
|
80
|
-
|
|
118
|
+
misspelled key such as `runz`. They take reeval's keys in snake_case at any depth (`min_lift`,
|
|
81
119
|
`delay_ms`); the keys of `env`, `headers` and the other maps of your own keep their spelling. Every
|
|
82
120
|
duration is seconds or a `timedelta`: `{"timeout": 90}`, `docker(start_timeout=timedelta(minutes=2))`,
|
|
83
121
|
`expect.poll(…, timeout=10)`. `docker()`, `fake_harness()`, `fake_judge()` and `plugin.*` return
|
|
84
122
|
values to pass as options, not data to edit.
|
|
85
123
|
|
|
124
|
+
`c.judge` takes the inputs the judge reads as keywords, and needs at least one: `diff=True`,
|
|
125
|
+
`contents=["src/**"]`, `output=True` with `on=result`, and so on. With none it raises `TypeError`.
|
|
126
|
+
|
|
127
|
+
```python
|
|
128
|
+
expect(c.judge("Is it valid JSON?", on=result, output=True)).to_pass()
|
|
129
|
+
```
|
|
130
|
+
|
|
86
131
|
### `def` and `async def` bodies
|
|
87
132
|
|
|
88
133
|
A `def` body gets a blocking context: `c.exec(…)` runs the command and returns its `ExecResult`,
|
|
@@ -17,14 +17,15 @@ from reeval_python.environment import (
|
|
|
17
17
|
plugin,
|
|
18
18
|
)
|
|
19
19
|
from reeval_python.errors import ReevalAssertionError, ReevalCallError
|
|
20
|
-
from reeval_python.expect import Expectation, expect
|
|
21
|
-
from reeval_python.options import EvalOptions, JudgeDefaults, JudgeOptions
|
|
20
|
+
from reeval_python.expect import Expectation, expect
|
|
21
|
+
from reeval_python.options import BestOf, EvalOptions, JudgeDefaults, JudgeOptions
|
|
22
22
|
from reeval_python.types import BackgroundHandle, Diff, ExecResult, FileChange, Turn, Verdict
|
|
23
23
|
|
|
24
24
|
__all__ = [
|
|
25
25
|
"DEFAULT_EGRESS_ALLOW",
|
|
26
26
|
"AttemptContext",
|
|
27
27
|
"BackgroundHandle",
|
|
28
|
+
"BestOf",
|
|
28
29
|
"Diff",
|
|
29
30
|
"DockerSandbox",
|
|
30
31
|
"Environment",
|
|
@@ -52,6 +53,5 @@ __all__ = [
|
|
|
52
53
|
"fake_judge",
|
|
53
54
|
"group",
|
|
54
55
|
"plugin",
|
|
55
|
-
"soft",
|
|
56
56
|
"todo",
|
|
57
57
|
]
|