Skip to content

Commit 982c5c9

Browse files
Copilottoolate28
andcommitted
Add demo script and update examples README
- Added import_traces_demo.py to demonstrate the function - Updated examples/README.md to document the new example - Demo shows all error handling scenarios Co-authored-by: toolate28 <105518313+toolate28@users.noreply.github.com>
1 parent fdac88b commit 982c5c9

2 files changed

Lines changed: 212 additions & 0 deletions

File tree

examples/README.md

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,34 @@ python3 examples/euler_number_usage.py
3131
- See [`docs/EULER_PRECISION_IMPACT_ANALYSIS.md`](../docs/EULER_PRECISION_IMPACT_ANALYSIS.md) for analysis of where this precision issue could manifest across the SpiralSafe ecosystem
3232
- Use `tools/scan_euler_precision.py` to scan for hardcoded approximations in your repositories
3333

34+
### import_traces_demo.py
35+
36+
Demonstrates how to safely import trace data from JSON files with proper error handling for missing required fields.
37+
38+
**Key Points:**
39+
- ✓ Validates required fields: `trace_id`, `state`, `input`, `output`
40+
- ✓ Provides clear error messages for missing/invalid data
41+
- ✓ Handles FileNotFoundError, JSONDecodeError, ValueError
42+
- ✓ Supports both single trace objects and arrays
43+
44+
**Usage:**
45+
```bash
46+
python3 examples/import_traces_demo.py
47+
```
48+
49+
**Topics Covered:**
50+
- Safe JSON import with validation
51+
- Error handling for missing fields
52+
- Defensive programming patterns
53+
- Clear error reporting
54+
55+
**Related Tests:**
56+
- `tests/test_import_traces.py` (pytest version)
57+
- `tests/test_import_traces_simple.py` (standalone version)
58+
59+
**Implementation:**
60+
- See `project-book.ipynb` for the full `import_traces()` function
61+
3462
---
3563

3664
## 🎯 Purpose

examples/import_traces_demo.py

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
"""
2+
Demonstration of the import_traces() function.
3+
4+
This script shows how to use the import_traces() function with various scenarios.
5+
"""
6+
import json
7+
import tempfile
8+
from pathlib import Path
9+
10+
11+
# The import_traces function (from project-book.ipynb)
12+
def import_traces(json_file_path):
13+
"""
14+
Import trace data from a JSON file with proper error handling.
15+
16+
See project-book.ipynb for full implementation.
17+
"""
18+
# Check if file exists
19+
if not Path(json_file_path).exists():
20+
raise FileNotFoundError(f"Trace file not found: {json_file_path}")
21+
22+
# Read and parse JSON
23+
try:
24+
with open(json_file_path, 'r', encoding='utf-8') as f:
25+
data = json.load(f)
26+
except json.JSONDecodeError as e:
27+
raise json.JSONDecodeError(
28+
f"Invalid JSON in file {json_file_path}: {str(e)}",
29+
e.doc,
30+
e.pos
31+
)
32+
33+
# Ensure data is a list
34+
if isinstance(data, dict):
35+
data = [data]
36+
elif not isinstance(data, list):
37+
raise ValueError(
38+
f"Expected JSON to contain a list or dict, got {type(data).__name__}"
39+
)
40+
41+
# Required fields for trace data
42+
required_fields = ['trace_id', 'state', 'input', 'output']
43+
44+
# Validate each trace
45+
validated_traces = []
46+
errors = []
47+
48+
for idx, trace in enumerate(data):
49+
if not isinstance(trace, dict):
50+
errors.append(f"Trace at index {idx} is not a dictionary: {type(trace).__name__}")
51+
continue
52+
53+
# Check for missing required fields
54+
missing_fields = [field for field in required_fields if field not in trace]
55+
56+
if missing_fields:
57+
error_msg = (
58+
f"Trace at index {idx} is missing required fields: {', '.join(missing_fields)}. "
59+
f"Available fields: {', '.join(trace.keys()) if trace.keys() else 'none'}. "
60+
f"Required fields are: {', '.join(required_fields)}"
61+
)
62+
errors.append(error_msg)
63+
continue
64+
65+
# Validate that required fields are not None
66+
none_fields = [field for field in required_fields if trace[field] is None]
67+
if none_fields:
68+
error_msg = (
69+
f"Trace at index {idx} has null values for required fields: {', '.join(none_fields)}"
70+
)
71+
errors.append(error_msg)
72+
continue
73+
74+
validated_traces.append(trace)
75+
76+
# If we have errors, raise a comprehensive error message
77+
if errors:
78+
error_summary = f"Found {len(errors)} invalid trace(s) in {json_file_path}:\n"
79+
error_summary += "\n".join(f" - {err}" for err in errors[:5])
80+
if len(errors) > 5:
81+
error_summary += f"\n ... and {len(errors) - 5} more error(s)"
82+
raise ValueError(error_summary)
83+
84+
if not validated_traces:
85+
raise ValueError(f"No valid traces found in {json_file_path}")
86+
87+
return validated_traces
88+
89+
90+
def demo():
91+
"""Run demonstration scenarios."""
92+
print("🔍 import_traces() Function Demonstration")
93+
print("=" * 60)
94+
95+
with tempfile.TemporaryDirectory() as tmp_dir:
96+
tmp_path = Path(tmp_dir)
97+
98+
# Demo 1: Valid trace import
99+
print("\n📋 Demo 1: Importing valid trace data")
100+
print("-" * 60)
101+
valid_file = tmp_path / "valid_traces.json"
102+
valid_data = [
103+
{
104+
"trace_id": "trace_001",
105+
"state": "completed",
106+
"input": {"query": "What is AI?"},
107+
"output": {"response": "AI stands for Artificial Intelligence"}
108+
},
109+
{
110+
"trace_id": "trace_002",
111+
"state": "pending",
112+
"input": {"query": "How does ML work?"},
113+
"output": {}
114+
}
115+
]
116+
valid_file.write_text(json.dumps(valid_data, indent=2))
117+
118+
try:
119+
traces = import_traces(str(valid_file))
120+
print(f"✅ Successfully imported {len(traces)} traces:")
121+
for trace in traces:
122+
print(f" - Trace {trace['trace_id']}: {trace['state']}")
123+
except Exception as e:
124+
print(f"❌ Error: {e}")
125+
126+
# Demo 2: Missing required field
127+
print("\n📋 Demo 2: Handling missing required fields")
128+
print("-" * 60)
129+
invalid_file = tmp_path / "invalid_traces.json"
130+
invalid_data = [{
131+
"trace_id": "trace_003",
132+
"state": "completed"
133+
# Missing 'input' and 'output' fields
134+
}]
135+
invalid_file.write_text(json.dumps(invalid_data, indent=2))
136+
137+
try:
138+
traces = import_traces(str(invalid_file))
139+
print(f"❌ Should have raised an error!")
140+
except ValueError as e:
141+
print(f"✅ Caught error as expected:")
142+
print(f" {str(e)[:200]}...")
143+
except Exception as e:
144+
print(f"❌ Unexpected error: {e}")
145+
146+
# Demo 3: File not found
147+
print("\n📋 Demo 3: Handling file not found")
148+
print("-" * 60)
149+
try:
150+
traces = import_traces("nonexistent_file.json")
151+
print(f"❌ Should have raised FileNotFoundError!")
152+
except FileNotFoundError as e:
153+
print(f"✅ Caught error as expected:")
154+
print(f" {e}")
155+
except Exception as e:
156+
print(f"❌ Unexpected error: {e}")
157+
158+
# Demo 4: Invalid JSON
159+
print("\n📋 Demo 4: Handling invalid JSON")
160+
print("-" * 60)
161+
malformed_file = tmp_path / "malformed.json"
162+
malformed_file.write_text("{not valid json")
163+
164+
try:
165+
traces = import_traces(str(malformed_file))
166+
print(f"❌ Should have raised JSONDecodeError!")
167+
except json.JSONDecodeError as e:
168+
print(f"✅ Caught error as expected:")
169+
print(f" Invalid JSON detected")
170+
except Exception as e:
171+
print(f"❌ Unexpected error: {e}")
172+
173+
print("\n" + "=" * 60)
174+
print("✨ Demonstration complete!")
175+
print("\nKey Features:")
176+
print(" • Validates required fields: trace_id, state, input, output")
177+
print(" • Provides clear error messages for missing/invalid data")
178+
print(" • Handles FileNotFoundError, JSONDecodeError, ValueError")
179+
print(" • Supports both single trace objects and arrays")
180+
print(" • Allows additional fields beyond required ones")
181+
182+
183+
if __name__ == "__main__":
184+
demo()

0 commit comments

Comments
 (0)