Skip to content

Commit fba0683

Browse files
Copilottoolate28
andcommitted
Add import_traces() function with error handling for missing required fields
- Added import_traces() function to project-book.ipynb - Validates required fields: trace_id, state, input, output - Provides clear error messages for missing/invalid fields - Handles FileNotFoundError, JSONDecodeError, and ValueError - Added comprehensive test suite in tests/ Co-authored-by: toolate28 <105518313+toolate28@users.noreply.github.com>
1 parent d0b6887 commit fba0683

3 files changed

Lines changed: 887 additions & 0 deletions

File tree

project-book.ipynb

Lines changed: 192 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,198 @@
294294
"outputs": [],
295295
"source": "@dataclass\nclass WaveSession:\n \"\"\"Represents a Wave collaboration session.\"\"\"\n session_id: str\n timestamp: str\n context: WaveContext\n system_prompt: str\n task: Optional[str] = None\n log_entries: List[Dict[str, Any]] = field(default_factory=list)\n \n def add_log(self, entry_type: str, content: str):\n \"\"\"Add a log entry to the session.\"\"\"\n self.log_entries.append({\n \"timestamp\": datetime.now().isoformat(),\n \"type\": entry_type,\n \"content\": content\n })\n \n def save(self, output_dir: str = \".claude/logs/sessions\"):\n \"\"\"Save the session log to a file.\"\"\"\n output_path = Path(output_dir)\n output_path.mkdir(parents=True, exist_ok=True)\n \n log_file = output_path / f\"session_{self.session_id}.json\"\n \n session_data = {\n \"session_id\": self.session_id,\n \"timestamp\": self.timestamp,\n \"task\": self.task,\n \"context\": self.context.to_dict(),\n \"system_prompt\": self.system_prompt,\n \"log_entries\": self.log_entries\n }\n \n with open(log_file, \"w\", encoding=\"utf-8\") as f:\n json.dump(session_data, f, indent=2)\n \n return str(log_file)\n\n\ndef create_wave_session(task: Optional[str] = None) -> WaveSession:\n \"\"\"\n Create a new Wave session with captured context.\n \n Args:\n task: Optional task description for the session\n \n Returns:\n WaveSession object\n \"\"\"\n ctx = get_wave_context()\n session_id = datetime.now().strftime(\"%Y%m%d_%H%M%S\")\n \n session = WaveSession(\n session_id=session_id,\n timestamp=ctx.timestamp,\n context=ctx,\n system_prompt=generate_system_prompt(ctx),\n task=task\n )\n \n session.add_log(\"session_start\", f\"Session created: {session_id}\")\n if task:\n session.add_log(\"task\", task)\n \n return session\n\n\n# Create a demo session\ndemo_session = create_wave_session(\"Explore Wave Toolkit Project Book\")\nprint(f\"\ud83d\udcdd Session Created: {demo_session.session_id}\")\nprint(f\" Task: {demo_session.task}\")\nprint(f\" Log Entries: {len(demo_session.log_entries)}\")"
296296
},
297+
{
298+
"cell_type": "code",
299+
"execution_count": null,
300+
"metadata": {},
301+
"outputs": [],
302+
"source": [
303+
"def import_traces(json_file_path: str) -> List[Dict[str, Any]]:",
304+
" \"\"\"",
305+
" Import trace data from a JSON file with proper error handling.",
306+
" ",
307+
" Handles JSON files containing trace data with required fields:",
308+
" - trace_id: Unique identifier for the trace",
309+
" - state: Current state of the trace",
310+
" - input: Input data for the trace",
311+
" - output: Output data from the trace",
312+
" ",
313+
" Args:",
314+
" json_file_path: Path to the JSON file containing trace data",
315+
" ",
316+
" Returns:",
317+
" List of trace dictionaries with validated fields",
318+
" ",
319+
" Raises:",
320+
" FileNotFoundError: If the JSON file doesn't exist",
321+
" json.JSONDecodeError: If the file contains invalid JSON",
322+
" ValueError: If required fields are missing or invalid",
323+
" ",
324+
" Example:",
325+
" >>> traces = import_traces(\"traces.json\")",
326+
" >>> for trace in traces:",
327+
" ... print(f\"Trace {trace['trace_id']}: {trace['state']}\")",
328+
" \"\"\"",
329+
" # Check if file exists",
330+
" if not Path(json_file_path).exists():",
331+
" raise FileNotFoundError(f\"Trace file not found: {json_file_path}\")",
332+
" ",
333+
" # Read and parse JSON",
334+
" try:",
335+
" with open(json_file_path, 'r', encoding='utf-8') as f:",
336+
" data = json.load(f)",
337+
" except json.JSONDecodeError as e:",
338+
" raise json.JSONDecodeError(",
339+
" f\"Invalid JSON in file {json_file_path}: {str(e)}\", ",
340+
" e.doc, ",
341+
" e.pos",
342+
" )",
343+
" ",
344+
" # Ensure data is a list",
345+
" if isinstance(data, dict):",
346+
" # If it's a single trace object, wrap it in a list",
347+
" data = [data]",
348+
" elif not isinstance(data, list):",
349+
" raise ValueError(",
350+
" f\"Expected JSON to contain a list or dict, got {type(data).__name__}\"",
351+
" )",
352+
" ",
353+
" # Required fields for trace data",
354+
" required_fields = ['trace_id', 'state', 'input', 'output']",
355+
" ",
356+
" # Validate each trace",
357+
" validated_traces = []",
358+
" errors = []",
359+
" ",
360+
" for idx, trace in enumerate(data):",
361+
" if not isinstance(trace, dict):",
362+
" errors.append(f\"Trace at index {idx} is not a dictionary: {type(trace).__name__}\")",
363+
" continue",
364+
" ",
365+
" # Check for missing required fields",
366+
" missing_fields = [field for field in required_fields if field not in trace]",
367+
" ",
368+
" if missing_fields:",
369+
" # Build a helpful error message",
370+
" error_msg = (",
371+
" f\"Trace at index {idx} is missing required fields: {', '.join(missing_fields)}. \"",
372+
" f\"Available fields: {', '.join(trace.keys()) if trace.keys() else 'none'}. \"",
373+
" f\"Required fields are: {', '.join(required_fields)}\"",
374+
" )",
375+
" errors.append(error_msg)",
376+
" continue",
377+
" ",
378+
" # Validate that required fields are not None",
379+
" none_fields = [field for field in required_fields if trace[field] is None]",
380+
" if none_fields:",
381+
" error_msg = (",
382+
" f\"Trace at index {idx} has null values for required fields: {', '.join(none_fields)}\"",
383+
" )",
384+
" errors.append(error_msg)",
385+
" continue",
386+
" ",
387+
" validated_traces.append(trace)",
388+
" ",
389+
" # If we have errors, raise a comprehensive error message",
390+
" if errors:",
391+
" error_summary = f\"Found {len(errors)} invalid trace(s) in {json_file_path}:\\n\"",
392+
" error_summary += \"\\n\".join(f\" - {err}\" for err in errors[:5]) # Show first 5 errors",
393+
" if len(errors) > 5:",
394+
" error_summary += f\"\\n ... and {len(errors) - 5} more error(s)\"",
395+
" raise ValueError(error_summary)",
396+
" ",
397+
" if not validated_traces:",
398+
" raise ValueError(f\"No valid traces found in {json_file_path}\")",
399+
" ",
400+
" return validated_traces",
401+
"",
402+
"",
403+
"# Example usage and test",
404+
"def _test_import_traces():",
405+
" \"\"\"Test the import_traces function with various scenarios.\"\"\"",
406+
" print(\"\\n\ud83e\uddea Testing import_traces function...\")",
407+
" ",
408+
" # Create test directory",
409+
" test_dir = Path(\".claude/test_traces\")",
410+
" test_dir.mkdir(parents=True, exist_ok=True)",
411+
" ",
412+
" # Test 1: Valid trace data",
413+
" valid_trace_file = test_dir / \"valid_traces.json\"",
414+
" valid_data = [",
415+
" {",
416+
" \"trace_id\": \"trace_001\",",
417+
" \"state\": \"completed\",",
418+
" \"input\": {\"query\": \"Hello\"},",
419+
" \"output\": {\"response\": \"Hi there!\"}",
420+
" },",
421+
" {",
422+
" \"trace_id\": \"trace_002\", ",
423+
" \"state\": \"pending\",",
424+
" \"input\": {\"query\": \"How are you?\"},",
425+
" \"output\": {}",
426+
" }",
427+
" ]",
428+
" with open(valid_trace_file, 'w') as f:",
429+
" json.dump(valid_data, f, indent=2)",
430+
" ",
431+
" try:",
432+
" traces = import_traces(str(valid_trace_file))",
433+
" print(f\"\u2705 Test 1 passed: Loaded {len(traces)} valid traces\")",
434+
" except Exception as e:",
435+
" print(f\"\u274c Test 1 failed: {e}\")",
436+
" ",
437+
" # Test 2: Missing required field",
438+
" invalid_trace_file = test_dir / \"invalid_traces.json\"",
439+
" invalid_data = [",
440+
" {",
441+
" \"trace_id\": \"trace_003\",",
442+
" \"state\": \"completed\",",
443+
" # Missing 'input' and 'output'",
444+
" }",
445+
" ]",
446+
" with open(invalid_trace_file, 'w') as f:",
447+
" json.dump(invalid_data, f, indent=2)",
448+
" ",
449+
" try:",
450+
" traces = import_traces(str(invalid_trace_file))",
451+
" print(f\"\u274c Test 2 failed: Should have raised ValueError for missing fields\")",
452+
" except ValueError as e:",
453+
" if \"missing required fields\" in str(e):",
454+
" print(f\"\u2705 Test 2 passed: Caught missing fields error\")",
455+
" else:",
456+
" print(f\"\u274c Test 2 failed: Wrong error message: {e}\")",
457+
" except Exception as e:",
458+
" print(f\"\u274c Test 2 failed: Unexpected error: {e}\")",
459+
" ",
460+
" # Test 3: File not found",
461+
" try:",
462+
" traces = import_traces(\"nonexistent_file.json\")",
463+
" print(f\"\u274c Test 3 failed: Should have raised FileNotFoundError\")",
464+
" except FileNotFoundError:",
465+
" print(f\"\u2705 Test 3 passed: Caught file not found error\")",
466+
" except Exception as e:",
467+
" print(f\"\u274c Test 3 failed: Unexpected error: {e}\")",
468+
" ",
469+
" # Test 4: Invalid JSON",
470+
" malformed_file = test_dir / \"malformed.json\"",
471+
" with open(malformed_file, 'w') as f:",
472+
" f.write(\"{invalid json content\")",
473+
" ",
474+
" try:",
475+
" traces = import_traces(str(malformed_file))",
476+
" print(f\"\u274c Test 4 failed: Should have raised JSONDecodeError\")",
477+
" except json.JSONDecodeError:",
478+
" print(f\"\u2705 Test 4 passed: Caught invalid JSON error\")",
479+
" except Exception as e:",
480+
" print(f\"\u274c Test 4 failed: Unexpected error: {e}\")",
481+
" ",
482+
" print(\"\\n\u2728 Testing complete!\")",
483+
"",
484+
"# Uncomment to run tests",
485+
"# _test_import_traces()",
486+
""
487+
]
488+
},
297489
{
298490
"cell_type": "markdown",
299491
"metadata": {},

0 commit comments

Comments
 (0)