From 3a79ceba93fb883c840ae966d181fdf16965d278 Mon Sep 17 00:00:00 2001 From: yusyus Date: Sat, 31 Jan 2026 22:17:19 +0300 Subject: [PATCH] fix: Handle None ai_analysis in how-to guide builder (PR #247) (#274) * Fix how-to guide builder edge case * Resolve merge conflict * fix: Handle None ai_analysis in how-to guide builder Fixes NoneType AttributeError when ai_analysis is explicitly None. The issue occurred when workflow.get('ai_analysis') returned None and code attempted to call .get() without checking if it was None first. Using 'workflow.get("ai_analysis", {})' only provides default {} when the key is missing, not when the value is None. Changed to use 'workflow.get("ai_analysis") or {}' pattern which handles both cases. Also added isinstance() type safety check in _extract_workflow_examples to gracefully handle malformed data. Changes: - _group_by_ai_tutorial_group: ai_analysis = workflow.get() or {} - _extract_workflow_examples: isinstance(ex, dict) check added - _create_guide: ai_analysis = primary_workflow.get() or {} (2 locations) - _generate_overview: ai_analysis = primary_workflow.get() or {} All 34 how-to guide builder tests passing. Closes #242 Co-authored-by: yashrastogi019-cell --------- Co-authored-by: yashrastogi019-cell --- src/skill_seekers/cli/how_to_guide_builder.py | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/skill_seekers/cli/how_to_guide_builder.py b/src/skill_seekers/cli/how_to_guide_builder.py index e865a85..271ae07 100644 --- a/src/skill_seekers/cli/how_to_guide_builder.py +++ b/src/skill_seekers/cli/how_to_guide_builder.py @@ -452,7 +452,7 @@ class WorkflowGrouper: ungrouped = [] for workflow in workflows: - ai_analysis = workflow.get("ai_analysis", {}) + ai_analysis = workflow.get("ai_analysis") or {} tutorial_group = ai_analysis.get("tutorial_group") if tutorial_group: @@ -908,7 +908,7 @@ class HowToGuideBuilder: def _extract_workflow_examples(self, examples: list[dict]) -> list[dict]: """Filter to workflow category only""" - return [ex for ex in examples if ex.get("category") == "workflow"] + return [ex for ex in examples if isinstance(ex, dict) and ex.get("category") == "workflow"] def _create_guide(self, title: str, workflows: list[dict], enhancer=None) -> HowToGuide: """ @@ -933,8 +933,10 @@ class HowToGuideBuilder: # Extract use case from AI analysis or title use_case = title - if primary_workflow.get("ai_analysis"): - use_case = primary_workflow["ai_analysis"].get("tutorial_group", title) + + ai_analysis = primary_workflow.get("ai_analysis") or {} + if ai_analysis: + use_case = ai_analysis.get("tutorial_group", title) # Determine overview overview = self._generate_overview(primary_workflow, workflows) @@ -967,19 +969,22 @@ class HowToGuideBuilder: ) # Add AI enhancements if enhancer is available + ai_analysis_for_enhancement = primary_workflow.get("ai_analysis") or {} if enhancer: - self._enhance_guide_with_ai(guide, primary_workflow.get("ai_analysis", {}), enhancer) - elif self.enhance_with_ai and primary_workflow.get("ai_analysis"): + self._enhance_guide_with_ai(guide, ai_analysis_for_enhancement, enhancer) + elif self.enhance_with_ai and ai_analysis_for_enhancement: # Fallback to old enhancement method (basic) - self._enhance_guide_with_ai_basic(guide, primary_workflow["ai_analysis"]) + self._enhance_guide_with_ai_basic(guide, ai_analysis_for_enhancement) return guide def _generate_overview(self, primary_workflow: dict, _all_workflows: list[dict]) -> str: """Generate guide overview""" # Try to get explanation from AI analysis - if primary_workflow.get("ai_analysis"): - explanation = primary_workflow["ai_analysis"].get("explanation") + + ai_analysis = primary_workflow.get("ai_analysis") or {} + if ai_analysis: + explanation = ai_analysis.get("explanation") if explanation: return explanation