"""Structured error types for GnommoEditor pipeline.""" from dataclasses import dataclass from pathlib import Path from typing import Optional class GnommoError(Exception): """Base exception for all GnommoEditor errors.""" pass @dataclass class ValidationIssue: """A single validation issue with location context.""" message: str file: Optional[Path] = None line: Optional[int] = None def __str__(self) -> str: parts = [] if self.file: parts.append(str(self.file)) if self.line is not None: parts.append(f"line {self.line}") location = ":".join(parts) if parts else "project" return f"[{location}] {self.message}" class ParseError(GnommoError): """Error during parsing of input files.""" def __init__(self, message: str, file: Optional[Path] = None, line: Optional[int] = None): self.issue = ValidationIssue(message, file, line) super().__init__(str(self.issue)) class ValidationError(GnommoError): """Error during validation stage. Can contain multiple issues.""" def __init__(self, issues: list[ValidationIssue]): self.issues = issues message = f"Validation failed with {len(issues)} error(s):\n" message += "\n".join(f" - {issue}" for issue in issues) super().__init__(message) class RenderError(GnommoError): """Error during rendering stage.""" def __init__(self, message: str, command: Optional[str] = None, stderr: Optional[str] = None): self.command = command self.stderr = stderr full_message = message if command: full_message += f"\nCommand: {command}" if stderr: full_message += f"\nFFmpeg output:\n{stderr}" super().__init__(full_message)