evalwise 0.1.0__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.
@@ -0,0 +1,38 @@
1
+ # Byte-compiled
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # Distribution
7
+ dist/
8
+ build/
9
+ *.egg-info/
10
+ *.egg
11
+
12
+ # Virtual environments
13
+ venv/
14
+ .venv/
15
+ env/
16
+
17
+ # IDE
18
+ .idea/
19
+ .vscode/
20
+ *.swp
21
+ *.swo
22
+
23
+ # Testing
24
+ .pytest_cache/
25
+ .coverage
26
+ htmlcov/
27
+ .mypy_cache/
28
+
29
+ # Model weights / downloaded artifacts
30
+ *.pt
31
+ *.pth
32
+ *.ckpt
33
+ *.safetensors
34
+ *.bin
35
+
36
+ # OS
37
+ .DS_Store
38
+ Thumbs.db
@@ -0,0 +1,255 @@
1
+ Metadata-Version: 2.5
2
+ Name: evalwise
3
+ Version: 0.1.0
4
+ Summary: Deterministic-first AI evaluation for text, image, audio, and video
5
+ Project-URL: Homepage, https://github.com/shreyaspj20/evalwise
6
+ Project-URL: Documentation, https://github.com/shreyaspj20/evalwise#readme
7
+ Project-URL: Repository, https://github.com/shreyaspj20/evalwise
8
+ Author-email: Shreyas Reddy <shreyaspj20@gmail.com>
9
+ License-Expression: MIT
10
+ Keywords: ai,evaluation,llm,machine-learning,ml,testing
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.10
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
19
+ Requires-Python: >=3.10
20
+ Requires-Dist: click>=8.0
21
+ Requires-Dist: httpx>=0.25
22
+ Requires-Dist: jsonschema>=4.0
23
+ Requires-Dist: langdetect>=1.0
24
+ Requires-Dist: pydantic>=2.0
25
+ Requires-Dist: rich>=13.0
26
+ Requires-Dist: textstat>=0.7
27
+ Provides-Extra: all
28
+ Requires-Dist: decord>=0.6; extra == 'all'
29
+ Requires-Dist: librosa>=0.10; extra == 'all'
30
+ Requires-Dist: open-clip-torch>=2.20; extra == 'all'
31
+ Requires-Dist: openai-whisper>=20231117; extra == 'all'
32
+ Requires-Dist: opencv-python>=4.8; extra == 'all'
33
+ Requires-Dist: pillow>=10.0; extra == 'all'
34
+ Requires-Dist: sentence-transformers>=2.0; extra == 'all'
35
+ Requires-Dist: soundfile>=0.12; extra == 'all'
36
+ Requires-Dist: torch>=2.0; extra == 'all'
37
+ Requires-Dist: transformers>=4.35; extra == 'all'
38
+ Requires-Dist: ultralytics>=8.0; extra == 'all'
39
+ Provides-Extra: audio
40
+ Requires-Dist: librosa>=0.10; extra == 'audio'
41
+ Requires-Dist: openai-whisper>=20231117; extra == 'audio'
42
+ Requires-Dist: soundfile>=0.12; extra == 'audio'
43
+ Provides-Extra: dev
44
+ Requires-Dist: mypy>=1.5; extra == 'dev'
45
+ Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
46
+ Requires-Dist: pytest>=7.0; extra == 'dev'
47
+ Requires-Dist: ruff>=0.1; extra == 'dev'
48
+ Provides-Extra: embeddings
49
+ Requires-Dist: sentence-transformers>=2.0; extra == 'embeddings'
50
+ Provides-Extra: image
51
+ Requires-Dist: open-clip-torch>=2.20; extra == 'image'
52
+ Requires-Dist: pillow>=10.0; extra == 'image'
53
+ Requires-Dist: torch>=2.0; extra == 'image'
54
+ Requires-Dist: transformers>=4.35; extra == 'image'
55
+ Requires-Dist: ultralytics>=8.0; extra == 'image'
56
+ Provides-Extra: nli
57
+ Requires-Dist: torch>=2.0; extra == 'nli'
58
+ Requires-Dist: transformers>=4.35; extra == 'nli'
59
+ Provides-Extra: video
60
+ Requires-Dist: decord>=0.6; extra == 'video'
61
+ Requires-Dist: opencv-python>=4.8; extra == 'video'
62
+ Description-Content-Type: text/markdown
63
+
64
+ # EvalWise
65
+
66
+ **Deterministic-first AI evaluation for text, image, audio, and video.**
67
+
68
+ The eval SDK that doesn't default to "ask another AI if this is good."
69
+
70
+ ```bash
71
+ pip install evalwise
72
+ ```
73
+
74
+ ## Why EvalWise?
75
+
76
+ Most eval tools jump straight to LLM-as-judge. That's:
77
+ - **Expensive** — every eval is another API call
78
+ - **Non-deterministic** — same input, different scores
79
+ - **Ungrounded** — "Score: 4/5" tells you nothing
80
+
81
+ EvalWise flips the default: **deterministic checks first, LLM-judge only when you have to.**
82
+
83
+ ## Quick Start
84
+
85
+ ```python
86
+ from evalwise import Suite, Assert
87
+
88
+ suite = Suite("summarization")
89
+
90
+ @suite.test
91
+ def test_format(response: str):
92
+ Assert.bullet_count(response, exactly=3)
93
+ Assert.word_count(response, max=200)
94
+ Assert.json_valid(response)
95
+
96
+ @suite.test
97
+ def test_factuality(response: str, source: str):
98
+ Assert.entails(response, source=source)
99
+ Assert.no_contradiction(response, source=source)
100
+
101
+ # Run against a dataset
102
+ results = suite.run(dataset="./golden_set.json")
103
+ results.assert_pass_rate(threshold=0.95)
104
+ ```
105
+
106
+ ## CLI
107
+
108
+ ```bash
109
+ # Run eval suite
110
+ evalwise run tests/test_summary.py --dataset golden.json
111
+
112
+ # Run in CI (exit code 1 on failure)
113
+ evalwise run tests/ --ci --threshold 0.95
114
+
115
+ # Create sample eval file
116
+ evalwise init
117
+ ```
118
+
119
+ ## Text Assertions
120
+
121
+ | Assertion | What it checks |
122
+ |-----------|----------------|
123
+ | `contains(text, substring)` | Substring present |
124
+ | `not_contains(text, substring)` | Substring absent |
125
+ | `regex(text, pattern)` | Pattern match |
126
+ | `json_valid(text)` | Parseable JSON |
127
+ | `json_schema(text, schema)` | Matches JSON schema |
128
+ | `word_count(text, min, max)` | Word count in range |
129
+ | `bullet_count(text, exactly)` | Bullet point count |
130
+ | `readability(text, min_score)` | Flesch Reading Ease |
131
+ | `language_is(text, "en")` | Correct language |
132
+ | `code_parses(text, "python")` | Valid syntax |
133
+ | `code_runs(text)` | Executes without error |
134
+ | `entails(text, source)` | Follows from source (NLI) |
135
+ | `no_contradiction(text, source)` | No contradictions |
136
+ | `embedding_similarity(text, ref)` | Semantic similarity |
137
+ | `urls_valid(text)` | All URLs return 2xx |
138
+
139
+ ## Image Assertions
140
+
141
+ Image evals cover prompt alignment, object detection, resolution/aspect ratio, NSFW safety, and similarity. Object detection uses **YOLO** via `ultralytics`.
142
+
143
+ ```python
144
+ from evalwise.image import ImageAssert
145
+
146
+ # Prompt alignment with CLIP
147
+ ImageAssert.clip_score(image, "a cat on a couch", threshold=0.25)
148
+
149
+ # Object detection
150
+ ImageAssert.contains_object(image, "cat", confidence=0.5)
151
+ ImageAssert.object_count(image, "person", exactly=2, confidence=0.5)
152
+
153
+ # Metadata
154
+ ImageAssert.resolution_is(image, width=1024, height=1024)
155
+ ImageAssert.resolution_min(image, width=512, height=512)
156
+ ImageAssert.aspect_ratio(image, ratio=1.0, tolerance=0.1)
157
+ ImageAssert.format_is(image, "PNG")
158
+
159
+ # Safety
160
+ ImageAssert.nsfw_below(image, threshold=0.1)
161
+
162
+ # Similarity to a reference image
163
+ ImageAssert.image_similarity(image, reference, threshold=0.8)
164
+ ```
165
+
166
+ ### Image generation example
167
+
168
+ `examples/test_image_generation.py` shows a complete eval suite. The dataset can include per-image thresholds and object lists:
169
+
170
+ ```json
171
+ {
172
+ "image_path": "./examples/sample_cat.jpeg",
173
+ "prompt": "a person sitting on a couch with a dog and a cat",
174
+ "min_width": 200,
175
+ "min_height": 100,
176
+ "required_objects": ["dog"],
177
+ "confidence": 0.25
178
+ }
179
+ ```
180
+
181
+ ## Audio Assertions
182
+
183
+ Audio assertions that use Whisper (`transcription_contains`, `transcription_equals`, `language_is`) require **ffmpeg** to be installed on your system in addition to the `evalwise[audio]` Python dependencies.
184
+
185
+ ```python
186
+ from evalwise.audio import AudioAssert
187
+
188
+ AudioAssert.transcription_contains(audio, "hello world")
189
+ AudioAssert.transcription_equals(audio, expected_text)
190
+ AudioAssert.language_is(audio, "en")
191
+ AudioAssert.duration_between(audio, min_sec=5, max_sec=30)
192
+ AudioAssert.sample_rate_is(audio, hz=44100)
193
+ AudioAssert.no_silence(audio, max_silence_sec=1.0)
194
+ ```
195
+
196
+ ## Installation
197
+
198
+ ```bash
199
+ # Core (text assertions)
200
+ pip install evalwise
201
+
202
+ # With image support
203
+ pip install evalwise[image]
204
+
205
+ # With audio support (also requires ffmpeg system binary)
206
+ pip install evalwise[audio]
207
+
208
+ # On macOS: brew install ffmpeg
209
+ # On Ubuntu: sudo apt install ffmpeg
210
+ # On Windows: winget install Gyan.FFmpeg
211
+
212
+ # Everything
213
+ pip install evalwise[all]
214
+ ```
215
+
216
+ ### What each extra gives you
217
+
218
+ | Extra | Capabilities enabled | Example tests |
219
+ |---|---|---|
220
+ | *(none)* | 22 of 25 text assertions | `test_basic.py` |
221
+ | `[nli]` | `Assert.entails`, `Assert.no_contradiction` | `test_summarization.py` |
222
+ | `[embeddings]` | `Assert.embedding_similarity` | — |
223
+ | `[image]` | CLIP, YOLO object detection, NSFW, resolution, similarity | `test_image_generation.py` |
224
+ | `[audio]` | Whisper transcription, language, duration, sample rate | `test_audio.py` |
225
+ | `[video]` | Video assertions (extra only, no example yet) | — |
226
+ | `[all]` | All of the above | — |
227
+
228
+ ### System dependencies
229
+
230
+ Some examples also require system binaries:
231
+
232
+ | Capability | System binary | Install |
233
+ |---|---|---|
234
+ | Audio transcription | `ffmpeg` | `brew install ffmpeg` / `apt install ffmpeg` |
235
+
236
+ ## Philosophy
237
+
238
+ 1. **Deterministic by default** — Same input, same result. Always.
239
+ 2. **Cheap first** — Check format, length, syntax before calling models.
240
+ 3. **Grounded scores** — Know exactly why something failed.
241
+ 4. **LLM-judge as last resort** — Only for truly subjective criteria.
242
+
243
+ ## Comparison
244
+
245
+ | | EvalWise | Promptfoo | Braintrust | LangSmith |
246
+ |---|--------|-----------|------------|-----------|
247
+ | Deterministic-first | ✓ | Partial | ✗ | ✗ |
248
+ | Image/Audio evals | ✓ | ✗ | ✗ | ✗ |
249
+ | Python-native | ✓ | YAML | SDK | SDK |
250
+ | No account required | ✓ | ✓ | ✗ | ✗ |
251
+ | OSS | ✓ | ✓ | Partial | ✗ |
252
+
253
+ ## License
254
+
255
+ MIT
@@ -0,0 +1,192 @@
1
+ # EvalWise
2
+
3
+ **Deterministic-first AI evaluation for text, image, audio, and video.**
4
+
5
+ The eval SDK that doesn't default to "ask another AI if this is good."
6
+
7
+ ```bash
8
+ pip install evalwise
9
+ ```
10
+
11
+ ## Why EvalWise?
12
+
13
+ Most eval tools jump straight to LLM-as-judge. That's:
14
+ - **Expensive** — every eval is another API call
15
+ - **Non-deterministic** — same input, different scores
16
+ - **Ungrounded** — "Score: 4/5" tells you nothing
17
+
18
+ EvalWise flips the default: **deterministic checks first, LLM-judge only when you have to.**
19
+
20
+ ## Quick Start
21
+
22
+ ```python
23
+ from evalwise import Suite, Assert
24
+
25
+ suite = Suite("summarization")
26
+
27
+ @suite.test
28
+ def test_format(response: str):
29
+ Assert.bullet_count(response, exactly=3)
30
+ Assert.word_count(response, max=200)
31
+ Assert.json_valid(response)
32
+
33
+ @suite.test
34
+ def test_factuality(response: str, source: str):
35
+ Assert.entails(response, source=source)
36
+ Assert.no_contradiction(response, source=source)
37
+
38
+ # Run against a dataset
39
+ results = suite.run(dataset="./golden_set.json")
40
+ results.assert_pass_rate(threshold=0.95)
41
+ ```
42
+
43
+ ## CLI
44
+
45
+ ```bash
46
+ # Run eval suite
47
+ evalwise run tests/test_summary.py --dataset golden.json
48
+
49
+ # Run in CI (exit code 1 on failure)
50
+ evalwise run tests/ --ci --threshold 0.95
51
+
52
+ # Create sample eval file
53
+ evalwise init
54
+ ```
55
+
56
+ ## Text Assertions
57
+
58
+ | Assertion | What it checks |
59
+ |-----------|----------------|
60
+ | `contains(text, substring)` | Substring present |
61
+ | `not_contains(text, substring)` | Substring absent |
62
+ | `regex(text, pattern)` | Pattern match |
63
+ | `json_valid(text)` | Parseable JSON |
64
+ | `json_schema(text, schema)` | Matches JSON schema |
65
+ | `word_count(text, min, max)` | Word count in range |
66
+ | `bullet_count(text, exactly)` | Bullet point count |
67
+ | `readability(text, min_score)` | Flesch Reading Ease |
68
+ | `language_is(text, "en")` | Correct language |
69
+ | `code_parses(text, "python")` | Valid syntax |
70
+ | `code_runs(text)` | Executes without error |
71
+ | `entails(text, source)` | Follows from source (NLI) |
72
+ | `no_contradiction(text, source)` | No contradictions |
73
+ | `embedding_similarity(text, ref)` | Semantic similarity |
74
+ | `urls_valid(text)` | All URLs return 2xx |
75
+
76
+ ## Image Assertions
77
+
78
+ Image evals cover prompt alignment, object detection, resolution/aspect ratio, NSFW safety, and similarity. Object detection uses **YOLO** via `ultralytics`.
79
+
80
+ ```python
81
+ from evalwise.image import ImageAssert
82
+
83
+ # Prompt alignment with CLIP
84
+ ImageAssert.clip_score(image, "a cat on a couch", threshold=0.25)
85
+
86
+ # Object detection
87
+ ImageAssert.contains_object(image, "cat", confidence=0.5)
88
+ ImageAssert.object_count(image, "person", exactly=2, confidence=0.5)
89
+
90
+ # Metadata
91
+ ImageAssert.resolution_is(image, width=1024, height=1024)
92
+ ImageAssert.resolution_min(image, width=512, height=512)
93
+ ImageAssert.aspect_ratio(image, ratio=1.0, tolerance=0.1)
94
+ ImageAssert.format_is(image, "PNG")
95
+
96
+ # Safety
97
+ ImageAssert.nsfw_below(image, threshold=0.1)
98
+
99
+ # Similarity to a reference image
100
+ ImageAssert.image_similarity(image, reference, threshold=0.8)
101
+ ```
102
+
103
+ ### Image generation example
104
+
105
+ `examples/test_image_generation.py` shows a complete eval suite. The dataset can include per-image thresholds and object lists:
106
+
107
+ ```json
108
+ {
109
+ "image_path": "./examples/sample_cat.jpeg",
110
+ "prompt": "a person sitting on a couch with a dog and a cat",
111
+ "min_width": 200,
112
+ "min_height": 100,
113
+ "required_objects": ["dog"],
114
+ "confidence": 0.25
115
+ }
116
+ ```
117
+
118
+ ## Audio Assertions
119
+
120
+ Audio assertions that use Whisper (`transcription_contains`, `transcription_equals`, `language_is`) require **ffmpeg** to be installed on your system in addition to the `evalwise[audio]` Python dependencies.
121
+
122
+ ```python
123
+ from evalwise.audio import AudioAssert
124
+
125
+ AudioAssert.transcription_contains(audio, "hello world")
126
+ AudioAssert.transcription_equals(audio, expected_text)
127
+ AudioAssert.language_is(audio, "en")
128
+ AudioAssert.duration_between(audio, min_sec=5, max_sec=30)
129
+ AudioAssert.sample_rate_is(audio, hz=44100)
130
+ AudioAssert.no_silence(audio, max_silence_sec=1.0)
131
+ ```
132
+
133
+ ## Installation
134
+
135
+ ```bash
136
+ # Core (text assertions)
137
+ pip install evalwise
138
+
139
+ # With image support
140
+ pip install evalwise[image]
141
+
142
+ # With audio support (also requires ffmpeg system binary)
143
+ pip install evalwise[audio]
144
+
145
+ # On macOS: brew install ffmpeg
146
+ # On Ubuntu: sudo apt install ffmpeg
147
+ # On Windows: winget install Gyan.FFmpeg
148
+
149
+ # Everything
150
+ pip install evalwise[all]
151
+ ```
152
+
153
+ ### What each extra gives you
154
+
155
+ | Extra | Capabilities enabled | Example tests |
156
+ |---|---|---|
157
+ | *(none)* | 22 of 25 text assertions | `test_basic.py` |
158
+ | `[nli]` | `Assert.entails`, `Assert.no_contradiction` | `test_summarization.py` |
159
+ | `[embeddings]` | `Assert.embedding_similarity` | — |
160
+ | `[image]` | CLIP, YOLO object detection, NSFW, resolution, similarity | `test_image_generation.py` |
161
+ | `[audio]` | Whisper transcription, language, duration, sample rate | `test_audio.py` |
162
+ | `[video]` | Video assertions (extra only, no example yet) | — |
163
+ | `[all]` | All of the above | — |
164
+
165
+ ### System dependencies
166
+
167
+ Some examples also require system binaries:
168
+
169
+ | Capability | System binary | Install |
170
+ |---|---|---|
171
+ | Audio transcription | `ffmpeg` | `brew install ffmpeg` / `apt install ffmpeg` |
172
+
173
+ ## Philosophy
174
+
175
+ 1. **Deterministic by default** — Same input, same result. Always.
176
+ 2. **Cheap first** — Check format, length, syntax before calling models.
177
+ 3. **Grounded scores** — Know exactly why something failed.
178
+ 4. **LLM-judge as last resort** — Only for truly subjective criteria.
179
+
180
+ ## Comparison
181
+
182
+ | | EvalWise | Promptfoo | Braintrust | LangSmith |
183
+ |---|--------|-----------|------------|-----------|
184
+ | Deterministic-first | ✓ | Partial | ✗ | ✗ |
185
+ | Image/Audio evals | ✓ | ✗ | ✗ | ✗ |
186
+ | Python-native | ✓ | YAML | SDK | SDK |
187
+ | No account required | ✓ | ✓ | ✗ | ✗ |
188
+ | OSS | ✓ | ✓ | Partial | ✗ |
189
+
190
+ ## License
191
+
192
+ MIT
@@ -0,0 +1,6 @@
1
+ [
2
+ {
3
+ "audio_path": "./examples/sample_audio.wav",
4
+ "expected_text": ""
5
+ }
6
+ ]
@@ -0,0 +1,14 @@
1
+ [
2
+ {
3
+ "response": "```python\nprint('Hello, World!')\n```",
4
+ "expected_output": "Hello, World!"
5
+ },
6
+ {
7
+ "response": "```python\nx = 5\ny = 3\nprint(x + y)\n```",
8
+ "expected_output": "8"
9
+ },
10
+ {
11
+ "response": "```python\ndef greet(name):\n return f'Hello, {name}!'\nprint(greet('EvalWise'))\n```",
12
+ "expected_output": "Hello, EvalWise!"
13
+ }
14
+ ]
@@ -0,0 +1,12 @@
1
+ [
2
+ {
3
+ "image_path": "./examples/sample_cat.jpeg",
4
+ "prompt": "a person in an orange shirt sitting on a couch holding a brown and white dog and petting a grey and white tabby cat",
5
+ "min_width": 200,
6
+ "min_height": 100,
7
+ "ratio": 1.4,
8
+ "tolerance": 0.1,
9
+ "required_objects": ["dog"],
10
+ "confidence": 0.25
11
+ }
12
+ ]
Binary file
Binary file
@@ -0,0 +1,14 @@
1
+ [
2
+ {
3
+ "response": "- The study found that exercise improves mental health\n- Participants who exercised 3x/week showed 40% reduction in anxiety\n- Results were consistent across age groups",
4
+ "source": "A new study published in the Journal of Mental Health examined 500 participants over 6 months. Researchers found that regular exercise significantly improves mental health outcomes. Participants who exercised three times per week showed a 40% reduction in anxiety symptoms compared to the control group. The positive effects were observed consistently across all age groups from 18 to 65."
5
+ },
6
+ {
7
+ "response": "- Climate change is accelerating faster than predicted\n- Arctic ice loss reached record levels in 2024\n- Scientists call for immediate action",
8
+ "source": "New data from NASA satellites reveals that climate change is accelerating at a rate faster than previous models predicted. Arctic sea ice reached its lowest extent on record in 2024, losing 15% more ice than the previous year. Climate scientists are calling for immediate and aggressive action to reduce carbon emissions, warning that current policies are insufficient to prevent catastrophic warming."
9
+ },
10
+ {
11
+ "response": "- Apple announced the iPhone 20 with holographic display\n- Battery life extended to 5 days\n- Price starts at $1,299",
12
+ "source": "Apple unveiled its latest smartphone, the iPhone 16, at its annual fall event. The new device features an improved OLED display with higher brightness and a new A18 chip. Battery life has been improved by 20% over the previous generation. The base model starts at $999, with the Pro version at $1,199."
13
+ }
14
+ ]
@@ -0,0 +1,29 @@
1
+ """Example: Evaluating speech/audio generation."""
2
+
3
+ from evalwise import Suite
4
+ from evalwise.audio import AudioAssert
5
+
6
+ suite = Suite("audio_evals")
7
+
8
+
9
+ @suite.test
10
+ def test_transcription(audio_path: str, expected_text: str):
11
+ """Check if speech contains expected text (using Whisper)."""
12
+ AudioAssert.transcription_contains(audio_path, expected_text)
13
+
14
+
15
+ @suite.test
16
+ def test_language(audio_path: str):
17
+ """Check audio is in English."""
18
+ AudioAssert.language_is(audio_path, "en")
19
+
20
+
21
+ @suite.test
22
+ def test_duration(audio_path: str):
23
+ """Check audio duration is reasonable."""
24
+ AudioAssert.duration_between(audio_path, min_sec=1, max_sec=60)
25
+
26
+
27
+ # To run (install deps first):
28
+ # pip install openai-whisper librosa soundfile
29
+ # evalwise run examples/test_audio.py --dataset examples/audio_data.json
@@ -0,0 +1,26 @@
1
+ """Basic example - no external dependencies required."""
2
+
3
+ from evalwise import Suite, Assert
4
+
5
+ suite = Suite("basic_evals")
6
+
7
+
8
+ @suite.test
9
+ def test_format(response: str):
10
+ """Test basic format checks."""
11
+ # These use only built-in Python - no dependencies
12
+ Assert.contains(response, "-") # Has bullet points
13
+ Assert.word_count(response, min=5, max=100)
14
+ Assert.line_count(response, min=1, max=10)
15
+
16
+
17
+ @suite.test
18
+ def test_structure(response: str):
19
+ """Test structure checks."""
20
+ Assert.bullet_count(response, min=1)
21
+ Assert.not_contains(response, "ERROR")
22
+ Assert.not_contains(response, "undefined")
23
+
24
+
25
+ # To run:
26
+ # evalwise run examples/test_basic.py --dataset examples/summarization_data.json
@@ -0,0 +1,53 @@
1
+ """Example: Evaluating code generation."""
2
+
3
+ import io
4
+ import re
5
+ import sys
6
+
7
+ from evalwise import Assert, Suite
8
+
9
+ suite = Suite("code_generation_evals")
10
+
11
+
12
+ def _extract_code(response: str) -> str:
13
+ """Extract code from a markdown block if present."""
14
+ code_match = re.search(r"```(?:\w+)?\n(.*?)```", response, re.DOTALL)
15
+ return code_match.group(1) if code_match else response
16
+
17
+
18
+ @suite.test
19
+ def test_syntax(response: str):
20
+ """Ensure generated code is syntactically valid."""
21
+ Assert.code_parses(response, language="python")
22
+
23
+
24
+ @suite.test
25
+ def test_execution(response: str):
26
+ """Ensure generated code executes without error."""
27
+ code = _extract_code(response)
28
+ Assert.code_runs(code)
29
+
30
+
31
+ @suite.test
32
+ def test_output(response: str, expected_output: str):
33
+ """Ensure code produces expected output."""
34
+ code = _extract_code(response)
35
+
36
+ old_stdout = sys.stdout
37
+ sys.stdout = buffer = io.StringIO()
38
+ try:
39
+ exec(code)
40
+ actual_output = buffer.getvalue().strip()
41
+ finally:
42
+ sys.stdout = old_stdout
43
+
44
+ Assert.custom(
45
+ passed=actual_output == expected_output,
46
+ name="output_matches",
47
+ expected=expected_output,
48
+ actual=actual_output,
49
+ )
50
+
51
+
52
+ # To run:
53
+ # evalwise run examples/test_code_generation.py --dataset examples/code_data.json