reeval-python 0.15.1__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.
Files changed (80) hide show
  1. {reeval_python-0.15.1 → reeval_python-0.16.1}/PKG-INFO +26 -10
  2. {reeval_python-0.15.1 → reeval_python-0.16.1}/README.md +25 -9
  3. {reeval_python-0.15.1 → reeval_python-0.16.1}/pyproject.toml +1 -1
  4. {reeval_python-0.15.1 → reeval_python-0.16.1}/src/reeval_python/__init__.py +3 -3
  5. {reeval_python-0.15.1 → reeval_python-0.16.1}/src/reeval_python/_wire.py +135 -113
  6. {reeval_python-0.15.1 → reeval_python-0.16.1}/src/reeval_python/aio.py +1 -9
  7. reeval_python-0.16.1/src/reeval_python/binaries.json +55 -0
  8. {reeval_python-0.15.1 → reeval_python-0.16.1}/src/reeval_python/checks.py +8 -1
  9. {reeval_python-0.15.1 → reeval_python-0.16.1}/src/reeval_python/context.py +39 -7
  10. {reeval_python-0.15.1 → reeval_python-0.16.1}/src/reeval_python/expect.py +51 -23
  11. {reeval_python-0.15.1 → reeval_python-0.16.1}/src/reeval_python/options.py +34 -5
  12. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/context/expect-fail.eval.py +1 -1
  13. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/context/expect-fail.sync.eval.py +1 -1
  14. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/context/expect.eval.py +2 -1
  15. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/context/expect.sync.eval.py +2 -1
  16. reeval_python-0.16.1/tests/context/judge.eval.py +14 -0
  17. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/context/judge.sync.eval.py +3 -3
  18. reeval_python-0.16.1/tests/declare/best-of.eval.py +24 -0
  19. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/declare/compare-questions.eval.py +10 -3
  20. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/declare/questions-attempts.eval.py +22 -5
  21. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/declare/questions-group.eval.py +8 -3
  22. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/declare/questions-state.eval.py +25 -6
  23. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/test_checks.py +26 -5
  24. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/test_conformance_context.py +12 -1
  25. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/test_runner_attempts.py +46 -5
  26. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/test_runner_checks.py +2 -1
  27. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/test_runner_json.py +2 -2
  28. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/test_runner_sdk.py +19 -3
  29. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/test_types.py +1 -1
  30. {reeval_python-0.15.1 → reeval_python-0.16.1}/uv.lock +1 -1
  31. reeval_python-0.15.1/src/reeval_python/binaries.json +0 -55
  32. reeval_python-0.15.1/tests/context/judge.eval.py +0 -10
  33. {reeval_python-0.15.1 → reeval_python-0.16.1}/.gitignore +0 -0
  34. {reeval_python-0.15.1 → reeval_python-0.16.1}/CHANGELOG.md +0 -0
  35. {reeval_python-0.15.1 → reeval_python-0.16.1}/LICENSE +0 -0
  36. {reeval_python-0.15.1 → reeval_python-0.16.1}/package.json +0 -0
  37. {reeval_python-0.15.1 → reeval_python-0.16.1}/src/reeval_python/__main__.py +0 -0
  38. {reeval_python-0.15.1 → reeval_python-0.16.1}/src/reeval_python/cli.py +0 -0
  39. {reeval_python-0.15.1 → reeval_python-0.16.1}/src/reeval_python/declare.py +0 -0
  40. {reeval_python-0.15.1 → reeval_python-0.16.1}/src/reeval_python/environment.py +0 -0
  41. {reeval_python-0.15.1 → reeval_python-0.16.1}/src/reeval_python/errors.py +0 -0
  42. {reeval_python-0.15.1 → reeval_python-0.16.1}/src/reeval_python/py.typed +0 -0
  43. {reeval_python-0.15.1 → reeval_python-0.16.1}/src/reeval_python/runner.py +0 -0
  44. {reeval_python-0.15.1 → reeval_python-0.16.1}/src/reeval_python/types.py +0 -0
  45. {reeval_python-0.15.1 → reeval_python-0.16.1}/src/reeval_python/wire.py +0 -0
  46. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/context/abort.eval.py +0 -0
  47. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/context/abort.sync.eval.py +0 -0
  48. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/context/exec-retries.eval.py +0 -0
  49. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/context/exec-retries.sync.eval.py +0 -0
  50. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/context/exec.eval.py +0 -0
  51. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/context/exec.sync.eval.py +0 -0
  52. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/context/files.eval.py +0 -0
  53. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/context/files.sync.eval.py +0 -0
  54. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/context/record.async.eval.py +0 -0
  55. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/context/record.eval.py +0 -0
  56. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/context/send.eval.py +0 -0
  57. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/context/send.sync.eval.py +0 -0
  58. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/context/sync-async.async.eval.py +0 -0
  59. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/context/sync-async.eval.py +0 -0
  60. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/declare/compare-variants.eval.py +0 -0
  61. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/declare/each-families.eval.py +0 -0
  62. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/declare/egress-cascade.eval.py +0 -0
  63. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/declare/environment-extend.eval.py +0 -0
  64. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/declare/environment-plugin-marketplace.eval.py +0 -0
  65. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/declare/environment-plugins.eval.py +0 -0
  66. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/declare/groups-skip-todo.eval.py +0 -0
  67. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/declare/revision.eval.py +0 -0
  68. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/declare/tags.eval.py +0 -0
  69. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/runner_process.py +0 -0
  70. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/stdio_host.py +0 -0
  71. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/test_api.py +0 -0
  72. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/test_cli.py +0 -0
  73. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/test_conformance_declare.py +0 -0
  74. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/test_load.py +0 -0
  75. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/test_patterns.py +0 -0
  76. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/test_python_wheels.py +0 -0
  77. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/test_runner_isolation.py +0 -0
  78. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/test_runner_misuse.py +0 -0
  79. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/test_runner_stdio.py +0 -0
  80. {reeval_python-0.15.1 → reeval_python-0.16.1}/tests/test_source.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: reeval-python
3
- Version: 0.15.1
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,24 +83,33 @@ 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`, soft checks,
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
- #### What a caught failure counts as
89
+ #### Checks carry on; `expect.require` is a gate
90
90
 
91
- A failed `expect` is a check the moment it fails: reeval records it before
92
- `ReevalAssertionError` reaches the body. One the body catches still fails the attempt when the
93
- body ends, as `expect.soft` does, and its error says the eval caught it. A plain `assert` the body
94
- catches records nothing, as in Python.
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.
95
104
 
96
105
  | The body catches | Recorded | Fails the attempt |
97
106
  |---|---|---|
98
- | a failed `expect(…)` | a failed check | yes, when the body ends |
107
+ | a failed `expect.require(…)` | a failed check | yes, when the body ends |
99
108
  | a failed `assert` | nothing | no |
100
109
  | neither (it escapes) | a failed check | yes |
101
110
 
102
111
  So retry with `expect.poll`, which retries the matcher and records only its final outcome, or with
103
- a plain `assert` or `if` in the loop, never `expect` in `try`/`except`:
112
+ a plain `assert` or `if` in the loop, never `expect.require` in `try`/`except`:
104
113
 
105
114
  ```python
106
115
  # Retries the command until it succeeds, for up to 10 seconds: one check.
@@ -136,6 +145,13 @@ duration is seconds or a `timedelta`: `{"timeout": 90}`, `docker(start_timeout=t
136
145
  `expect.poll(…, timeout=10)`. `docker()`, `fake_harness()`, `fake_judge()` and `plugin.*` return
137
146
  values to pass as options, not data to edit.
138
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
+
139
155
  ### `def` and `async def` bodies
140
156
 
141
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,24 +59,33 @@ 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`, soft checks,
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
- #### What a caught failure counts as
65
+ #### Checks carry on; `expect.require` is a gate
66
66
 
67
- A failed `expect` is a check the moment it fails: reeval records it before
68
- `ReevalAssertionError` reaches the body. One the body catches still fails the attempt when the
69
- body ends, as `expect.soft` does, and its error says the eval caught it. A plain `assert` the body
70
- catches records nothing, as in Python.
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.
71
80
 
72
81
  | The body catches | Recorded | Fails the attempt |
73
82
  |---|---|---|
74
- | a failed `expect(…)` | a failed check | yes, when the body ends |
83
+ | a failed `expect.require(…)` | a failed check | yes, when the body ends |
75
84
  | a failed `assert` | nothing | no |
76
85
  | neither (it escapes) | a failed check | yes |
77
86
 
78
87
  So retry with `expect.poll`, which retries the matcher and records only its final outcome, or with
79
- a plain `assert` or `if` in the loop, never `expect` in `try`/`except`:
88
+ a plain `assert` or `if` in the loop, never `expect.require` in `try`/`except`:
80
89
 
81
90
  ```python
82
91
  # Retries the command until it succeeds, for up to 10 seconds: one check.
@@ -112,6 +121,13 @@ duration is seconds or a `timedelta`: `{"timeout": 90}`, `docker(start_timeout=t
112
121
  `expect.poll(…, timeout=10)`. `docker()`, `fake_harness()`, `fake_judge()` and `plugin.*` return
113
122
  values to pass as options, not data to edit.
114
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
+
115
131
  ### `def` and `async def` bodies
116
132
 
117
133
  A `def` body gets a blocking context: `c.exec(…)` runs the command and returns its `ExecResult`,
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "reeval-python"
3
- version = "0.15.1"
3
+ version = "0.16.1"
4
4
  description = "Python authoring SDK for reeval (*.eval.py eval files)"
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.11"
@@ -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, soft
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
  ]