Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,34 @@ python3 examples/euler_number_usage.py
- 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
- Use `tools/scan_euler_precision.py` to scan for hardcoded approximations in your repositories

### import_traces_demo.py

Demonstrates how to safely import trace data from JSON files with proper error handling for missing required fields.

**Key Points:**
- ✓ Validates required fields: `trace_id`, `state`, `input`, `output`
- ✓ Provides clear error messages for missing/invalid data
- ✓ Handles FileNotFoundError, JSONDecodeError, ValueError
- ✓ Supports both single trace objects and arrays

**Usage:**
```bash
python3 examples/import_traces_demo.py
```

**Topics Covered:**
- Safe JSON import with validation
- Error handling for missing fields
- Defensive programming patterns
- Clear error reporting

**Related Tests:**
- `tests/test_import_traces.py` (pytest version)
- `tests/test_import_traces_simple.py` (standalone version)

**Implementation:**
- See `project-book.ipynb` for the full `import_traces()` function

---

## 🎯 Purpose
Expand Down
184 changes: 184 additions & 0 deletions examples/import_traces_demo.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
"""
Demonstration of the import_traces() function.

This script shows how to use the import_traces() function with various scenarios.
"""
import json
import tempfile
from pathlib import Path


# The import_traces function (from project-book.ipynb)
def import_traces(json_file_path):
Comment on lines +9 to +12
Copy link

Copilot AI Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function signature is missing type hints that are present in the other implementations. The parameter should be annotated as json_file_path: str and the return type should be -> List[Dict[str, Any]] for consistency with the implementations in tests/test_import_traces.py and tests/test_import_traces_simple.py.

Suggested change
# The import_traces function (from project-book.ipynb)
def import_traces(json_file_path):
from typing import Any, Dict, List
# The import_traces function (from project-book.ipynb)
def import_traces(json_file_path: str) -> List[Dict[str, Any]]:

Copilot uses AI. Check for mistakes.
Comment on lines +9 to +12
Copy link

Copilot AI Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The file is missing the type hints imports. Add from typing import List, Dict, Any to support the type annotations that should be added to the function signature.

Suggested change
# The import_traces function (from project-book.ipynb)
def import_traces(json_file_path):
from typing import List, Dict, Any
# The import_traces function (from project-book.ipynb)
def import_traces(json_file_path: str) -> List[Dict[str, Any]]:

Copilot uses AI. Check for mistakes.
"""
Import trace data from a JSON file with proper error handling.

See project-book.ipynb for full implementation.
"""
# Check if file exists
if not Path(json_file_path).exists():
raise FileNotFoundError(f"Trace file not found: {json_file_path}")

# Read and parse JSON
try:
with open(json_file_path, 'r', encoding='utf-8') as f:
data = json.load(f)
except json.JSONDecodeError as e:
raise json.JSONDecodeError(
f"Invalid JSON in file {json_file_path}: {str(e)}",
e.doc,
e.pos
)

# Ensure data is a list
if isinstance(data, dict):
data = [data]
elif not isinstance(data, list):
raise ValueError(
f"Expected JSON to contain a list or dict, got {type(data).__name__}"
)

# Required fields for trace data
required_fields = ['trace_id', 'state', 'input', 'output']

# Validate each trace
validated_traces = []
errors = []

for idx, trace in enumerate(data):
if not isinstance(trace, dict):
errors.append(f"Trace at index {idx} is not a dictionary: {type(trace).__name__}")
continue

# Check for missing required fields
missing_fields = [field for field in required_fields if field not in trace]

if missing_fields:
error_msg = (
f"Trace at index {idx} is missing required fields: {', '.join(missing_fields)}. "
f"Available fields: {', '.join(trace.keys()) if trace.keys() else 'none'}. "
Copy link

Copilot AI Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition if trace.keys() will always evaluate to True because dict.keys() returns a dict_keys view object which is always truthy, even for an empty dict. This means the 'none' fallback will never be shown. The condition should be if trace or if len(trace) > 0 to properly check if the dictionary has any keys.

Suggested change
f"Available fields: {', '.join(trace.keys()) if trace.keys() else 'none'}. "
f"Available fields: {', '.join(trace.keys()) if trace else 'none'}. "

Copilot uses AI. Check for mistakes.
f"Required fields are: {', '.join(required_fields)}"
)
errors.append(error_msg)
continue

# Validate that required fields are not None
none_fields = [field for field in required_fields if trace[field] is None]
if none_fields:
error_msg = (
f"Trace at index {idx} has null values for required fields: {', '.join(none_fields)}"
)
errors.append(error_msg)
continue

validated_traces.append(trace)

# If we have errors, raise a comprehensive error message
if errors:
error_summary = f"Found {len(errors)} invalid trace(s) in {json_file_path}:\n"
error_summary += "\n".join(f" - {err}" for err in errors[:5])
if len(errors) > 5:
error_summary += f"\n ... and {len(errors) - 5} more error(s)"
raise ValueError(error_summary)

if not validated_traces:
raise ValueError(f"No valid traces found in {json_file_path}")

return validated_traces


def demo():
"""Run demonstration scenarios."""
print("🔍 import_traces() Function Demonstration")
print("=" * 60)

with tempfile.TemporaryDirectory() as tmp_dir:
tmp_path = Path(tmp_dir)

# Demo 1: Valid trace import
print("\n📋 Demo 1: Importing valid trace data")
print("-" * 60)
valid_file = tmp_path / "valid_traces.json"
valid_data = [
{
"trace_id": "trace_001",
"state": "completed",
"input": {"query": "What is AI?"},
"output": {"response": "AI stands for Artificial Intelligence"}
},
{
"trace_id": "trace_002",
"state": "pending",
"input": {"query": "How does ML work?"},
"output": {}
}
]
valid_file.write_text(json.dumps(valid_data, indent=2))

try:
traces = import_traces(str(valid_file))
print(f"✅ Successfully imported {len(traces)} traces:")
for trace in traces:
print(f" - Trace {trace['trace_id']}: {trace['state']}")
except Exception as e:
print(f"❌ Error: {e}")

# Demo 2: Missing required field
print("\n📋 Demo 2: Handling missing required fields")
print("-" * 60)
invalid_file = tmp_path / "invalid_traces.json"
invalid_data = [{
"trace_id": "trace_003",
"state": "completed"
# Missing 'input' and 'output' fields
}]
invalid_file.write_text(json.dumps(invalid_data, indent=2))

try:
traces = import_traces(str(invalid_file))
Copy link

Copilot AI Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assignment to 'traces' is unnecessary as it is redefined before this value is used.
This assignment to 'traces' is unnecessary as it is redefined before this value is used.

Copilot uses AI. Check for mistakes.
print(f"❌ Should have raised an error!")
except ValueError as e:
print(f"✅ Caught error as expected:")
print(f" {str(e)[:200]}...")
except Exception as e:
print(f"❌ Unexpected error: {e}")

# Demo 3: File not found
print("\n📋 Demo 3: Handling file not found")
print("-" * 60)
try:
traces = import_traces("nonexistent_file.json")
Copy link

Copilot AI Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assignment to 'traces' is unnecessary as it is redefined before this value is used.

Suggested change
traces = import_traces("nonexistent_file.json")
import_traces("nonexistent_file.json")

Copilot uses AI. Check for mistakes.
print(f"❌ Should have raised FileNotFoundError!")
except FileNotFoundError as e:
print(f"✅ Caught error as expected:")
print(f" {e}")
except Exception as e:
print(f"❌ Unexpected error: {e}")

# Demo 4: Invalid JSON
print("\n📋 Demo 4: Handling invalid JSON")
print("-" * 60)
malformed_file = tmp_path / "malformed.json"
malformed_file.write_text("{not valid json")

try:
traces = import_traces(str(malformed_file))
Copy link

Copilot AI Jan 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable traces is not used.

Suggested change
traces = import_traces(str(malformed_file))
import_traces(str(malformed_file))

Copilot uses AI. Check for mistakes.
print(f"❌ Should have raised JSONDecodeError!")
except json.JSONDecodeError as e:
print(f"✅ Caught error as expected:")
print(f" Invalid JSON detected")
except Exception as e:
print(f"❌ Unexpected error: {e}")

print("\n" + "=" * 60)
print("✨ Demonstration complete!")
print("\nKey Features:")
print(" • Validates required fields: trace_id, state, input, output")
print(" • Provides clear error messages for missing/invalid data")
print(" • Handles FileNotFoundError, JSONDecodeError, ValueError")
print(" • Supports both single trace objects and arrays")
print(" • Allows additional fields beyond required ones")


if __name__ == "__main__":
demo()
Loading
Loading