Parse dictionary into TaskPlan with validation.
(plan_data: Dict[str, Any])
| 1111 | |
| 1112 | |
| 1113 | def parse_task_plan(plan_data: Dict[str, Any]) -> TaskPlan: |
| 1114 | """Parse dictionary into TaskPlan with validation.""" |
| 1115 | try: |
| 1116 | # Handle case where plan_data might be None or empty |
| 1117 | if not plan_data: |
| 1118 | return TaskPlan(todo=[], in_progress=None, done=[]) |
| 1119 | |
| 1120 | # Parse todo items with careful validation |
| 1121 | todo_dates = [] |
| 1122 | for dt_str in plan_data.get('todo', []): |
| 1123 | if dt_str: |
| 1124 | parsed_dt = parse_datetime(dt_str) |
| 1125 | if parsed_dt: |
| 1126 | # Ensure datetime is timezone-aware (use the user's timezone if not specified) |
| 1127 | if parsed_dt.tzinfo is None: |
| 1128 | parsed_dt = _localize_task_datetime(parsed_dt) |
| 1129 | todo_dates.append(parsed_dt) |
| 1130 | |
| 1131 | # Parse in_progress with validation |
| 1132 | in_progress = None |
| 1133 | if plan_data.get('in_progress'): |
| 1134 | in_progress = parse_datetime(plan_data.get('in_progress')) |
| 1135 | # Ensure datetime is timezone-aware |
| 1136 | if in_progress and in_progress.tzinfo is None: |
| 1137 | in_progress = _localize_task_datetime(in_progress) |
| 1138 | |
| 1139 | # Parse done items with validation |
| 1140 | done_dates = [] |
| 1141 | for dt_str in plan_data.get('done', []): |
| 1142 | if dt_str: |
| 1143 | parsed_dt = parse_datetime(dt_str) |
| 1144 | if parsed_dt: |
| 1145 | # Ensure datetime is timezone-aware |
| 1146 | if parsed_dt.tzinfo is None: |
| 1147 | parsed_dt = _localize_task_datetime(parsed_dt) |
| 1148 | done_dates.append(parsed_dt) |
| 1149 | |
| 1150 | # Sort dates for better usability |
| 1151 | todo_dates.sort() |
| 1152 | done_dates.sort(reverse=True) # Most recent first for done items |
| 1153 | |
| 1154 | # Cast to ensure type safety |
| 1155 | todo_dates_cast: list[datetime] = cast(list[datetime], todo_dates) |
| 1156 | done_dates_cast: list[datetime] = cast(list[datetime], done_dates) |
| 1157 | |
| 1158 | return TaskPlan.create( |
| 1159 | todo=todo_dates_cast, |
| 1160 | in_progress=in_progress, |
| 1161 | done=done_dates_cast |
| 1162 | ) |
| 1163 | except Exception as e: |
| 1164 | PrintStyle.error( |
| 1165 | f"Error parsing task plan: {e}" |
| 1166 | ) |
| 1167 | # Return empty plan instead of failing |
| 1168 | return TaskPlan(todo=[], in_progress=None, done=[]) |
| 1169 | |
| 1170 |