"""Custom exceptions for VoIdea application.""" from typing import Any class AppError(Exception): """Base application exception. All business errors inherit from this class. Does not contain HTTP status codes (those are in API layer). """ def __init__( self, message: str, code: str = "GENERAL_ERROR", details: dict | None = None, ) -> None: self.message = message self.code = code self.details = details or {} super().__init__(message) def to_dict(self) -> dict: """Convert exception to dictionary.""" return { "error": self.code, "message": self.message, "details": self.details, } class NotFoundError(AppError): """Resource not found error.""" def __init__( self, message: str = "Resource not found", code: str = "NOT_FOUND", resource: str | None = None, resource_id: str | None = None, ) -> None: details = {} if resource: details["resource"] = resource if resource_id: details["resource_id"] = resource_id super().__init__(message, code, details) class PermissionError(AppError): """Permission denied error.""" def __init__( self, message: str = "Permission denied", code: str = "PERMISSION_DENIED", ) -> None: super().__init__(message, code) class ValidationError(AppError): """Validation error.""" def __init__( self, message: str = "Validation error", code: str = "VALIDATION_ERROR", field: str | None = None, value: Any = None, ) -> None: details = {} if field: details["field"] = field if value is not None: details["value"] = str(value) super().__init__(message, code, details) class AuthenticationError(AppError): """Authentication error.""" def __init__( self, message: str = "Authentication failed", code: str = "AUTH_FAILED", ) -> None: super().__init__(message, code) class QuotaExceededError(AppError): """Quota exceeded error.""" def __init__( self, message: str = "Quota exceeded", code: str = "QUOTA_EXCEEDED", limit: int | None = None, used: int | None = None, ) -> None: details = {} if limit is not None: details["limit"] = limit if used is not None: details["used"] = used super().__init__(message, code, details) class ExternalServiceError(AppError): """External service error (AI, OAuth, etc.).""" def __init__( self, message: str = "External service error", code: str = "EXTERNAL_SERVICE_ERROR", service: str | None = None, ) -> None: details = {} if service: details["service"] = service super().__init__(message, code, details) class RateLimitError(AppError): """Rate limit exceeded error.""" def __init__( self, message: str = "Rate limit exceeded", code: str = "RATE_LIMIT_EXCEEDED", retry_after: int | None = None, ) -> None: details = {} if retry_after: details["retry_after"] = retry_after super().__init__(message, code, details) # Import for type hints from typing import Any