"""Custom exceptions for CiteScan.""" class CiteScanException(Exception): """Base exception for CiteScan.""" def __init__(self, message: str, details: dict | None = None): """Initialize exception. Args: message: Error message details: Optional additional details """ self.message = message self.details = details or {} super().__init__(self.message) class FetcherException(CiteScanException): """Exception raised by fetchers.""" def __init__(self, message: str, source: str, details: dict | None = None): """Initialize fetcher exception. Args: message: Error message source: Fetcher source (e.g., 'arxiv', 'crossref') details: Optional additional details """ self.source = source super().__init__(message, details) class ParserException(CiteScanException): """Exception raised by parsers.""" pass class ValidationException(CiteScanException): """Exception raised during validation.""" pass class RateLimitException(FetcherException): """Exception raised when rate limit is exceeded.""" def __init__(self, source: str, retry_after: int | None = None): """Initialize rate limit exception. Args: source: Fetcher source retry_after: Seconds to wait before retry """ self.retry_after = retry_after message = f"Rate limit exceeded for {source}" if retry_after: message += f". Retry after {retry_after} seconds" super().__init__(message, source) class TimeoutException(FetcherException): """Exception raised when request times out.""" def __init__(self, source: str, timeout: int): """Initialize timeout exception. Args: source: Fetcher source timeout: Timeout value in seconds """ message = f"Request to {source} timed out after {timeout} seconds" super().__init__(message, source)