Pre-publication review draft
日常訳NICHIJOYAKU日本語 ↗

OPEN SOURCE

software/src/exceptions.py

Read on this site and download the files you need.

Nichijoyaku was created using AI. A complete review by human biblical-language and biblical-studies specialists has not been established. Read alongside established translations and original-language resources.

← Back to the open-source guide

software/src/exceptions.py302 linesDownload this file ↓

This is the same source included in the download. Each line number is a link you can save or share.

File verification detailsSHA-256 b6e76324365682d6a6eb97c1cf616a4d8bbab425872ff4d8d1b58b3ef2927b9a
1"""Custom exception hierarchy for the Bible translator.23Provides specific exception types for different error scenarios to enable4proper error handling and recovery strategies.5"""67from __future__ import annotations8910class TranslationError(Exception):11    """Base exception for all translation-related errors."""1213    def __init__(self, message: str, details: dict | None = None) -> None:14        """Initialize the translation error.1516        Args:17            message: Human-readable error message.18            details: Optional dictionary with additional error details.19        """20        super().__init__(message)21        self.details = details or {}222324class ClaudeAPIError(TranslationError):25    """Error communicating with Claude CLI/API."""2627    def __init__(28        self,29        message: str,30        stderr: str | None = None,31        return_code: int | None = None,32    ) -> None:33        """Initialize the Claude API error.3435        Args:36            message: Human-readable error message.37            stderr: Standard error output from the CLI.38            return_code: Process return code.39        """40        details = {41            "stderr": stderr,42            "return_code": return_code,43        }44        super().__init__(message, details)45        self.stderr = stderr46        self.return_code = return_code474849class RateLimitError(ClaudeAPIError):50    """Rate limit exceeded when calling Claude."""5152    def __init__(53        self,54        message: str = "Rate limit exceeded",55        retry_after: float | None = None,56    ) -> None:57        """Initialize the rate limit error.5859        Args:60            message: Human-readable error message.61            retry_after: Suggested wait time in seconds before retrying.62        """63        super().__init__(message)64        self.retry_after = retry_after65        self.details["retry_after"] = retry_after666768class ModelNotFoundError(ClaudeAPIError):69    """Requested model is not available."""7071    def __init__(self, model: str) -> None:72        """Initialize the model not found error.7374        Args:75            model: The model identifier that was not found.76        """77        super().__init__(f"Model not found: {model}")78        self.model = model79        self.details["model"] = model808182class CLINotFoundError(ClaudeAPIError):83    """Claude CLI is not installed or not in PATH."""8485    def __init__(self) -> None:86        """Initialize the CLI not found error."""87        super().__init__(88            "Claude CLI not found. Install with: npm install -g @anthropic-ai/claude-code"89        )909192class VerseNotFoundError(TranslationError):93    """Requested verse does not exist."""9495    def __init__(self, book: str, chapter: int, verse: int) -> None:96        """Initialize the verse not found error.9798        Args:99            book: Book name.100            chapter: Chapter number.101            verse: Verse number.102        """103        super().__init__(f"Verse not found: {book} {chapter}:{verse}")104        self.book = book105        self.chapter = chapter106        self.verse = verse107        self.details = {"book": book, "chapter": chapter, "verse": verse}108109110class InvalidReferenceError(TranslationError):111    """Invalid verse reference format."""112113    def __init__(self, reference: str, reason: str | None = None) -> None:114        """Initialize the invalid reference error.115116        Args:117            reference: The malformed reference string.118            reason: Optional explanation of what's wrong.119        """120        msg = f"Invalid reference format: {reference}"121        if reason:122            msg += f" ({reason})"123        super().__init__(msg)124        self.reference = reference125        self.reason = reason126        self.details = {"reference": reference, "reason": reason}127128129class ChunkParsingError(TranslationError):130    """Error parsing chunk/pericope translation response."""131132    def __init__(133        self,134        message: str,135        response: str | None = None,136        expected_verses: list[str] | None = None,137    ) -> None:138        """Initialize the chunk parsing error.139140        Args:141            message: Human-readable error message.142            response: The raw response that failed to parse.143            expected_verses: List of verse references that were expected.144        """145        super().__init__(message)146        self.response = response147        self.expected_verses = expected_verses148        self.details = {149            "response_preview": response[:500] if response else None,150            "expected_verses": expected_verses,151        }152153154class PericopeNotFoundError(TranslationError):155    """Requested pericope does not exist."""156157    def __init__(self, pericope_id: str) -> None:158        """Initialize the pericope not found error.159160        Args:161            pericope_id: The pericope identifier that was not found.162        """163        super().__init__(f"Pericope not found: {pericope_id}")164        self.pericope_id = pericope_id165        self.details = {"pericope_id": pericope_id}166167168class EvaluationError(TranslationError):169    """Error during translation evaluation."""170171    def __init__(172        self,173        message: str,174        verse_ref: str | None = None,175        dimension: str | None = None,176    ) -> None:177        """Initialize the evaluation error.178179        Args:180            message: Human-readable error message.181            verse_ref: The verse being evaluated.182            dimension: The evaluation dimension that failed.183        """184        super().__init__(message)185        self.verse_ref = verse_ref186        self.dimension = dimension187        self.details = {"verse_ref": verse_ref, "dimension": dimension}188189190class QualityThresholdError(TranslationError):191    """Translation failed to meet quality threshold."""192193    def __init__(194        self,195        message: str,196        score: float,197        threshold: float,198        dimension: str | None = None,199    ) -> None:200        """Initialize the quality threshold error.201202        Args:203            message: Human-readable error message.204            score: The actual score achieved.205            threshold: The required minimum score.206            dimension: The dimension that failed (if specific).207        """208        super().__init__(message)209        self.score = score210        self.threshold = threshold211        self.dimension = dimension212        self.details = {213            "score": score,214            "threshold": threshold,215            "dimension": dimension,216        }217218219class StorageError(TranslationError):220    """Error reading or writing translation data."""221222    def __init__(223        self,224        message: str,225        path: str | None = None,226        operation: str | None = None,227    ) -> None:228        """Initialize the storage error.229230        Args:231            message: Human-readable error message.232            path: The file path involved.233            operation: The operation that failed (read/write).234        """235        super().__init__(message)236        self.path = path237        self.operation = operation238        self.details = {"path": path, "operation": operation}239240241class GlossaryMatchError(TranslationError):242    """Error in glossary term matching."""243244    def __init__(self, message: str, term: str | None = None) -> None:245        """Initialize the glossary match error.246247        Args:248            message: Human-readable error message.249            term: The term being matched.250        """251        super().__init__(message)252        self.term = term253        self.details = {"term": term}254255256class ConfigurationError(TranslationError):257    """Error in configuration loading or validation."""258259    def __init__(self, message: str, config_key: str | None = None) -> None:260        """Initialize the configuration error.261262        Args:263            message: Human-readable error message.264            config_key: The configuration key that caused the error.265        """266        super().__init__(message)267        self.config_key = config_key268        self.details = {"config_key": config_key}269270271def classify_claude_error(stderr: str, return_code: int) -> ClaudeAPIError:272    """Classify a Claude CLI error based on stderr and return code.273274    Args:275        stderr: Standard error output from the CLI.276        return_code: Process return code.277278    Returns:279        Appropriate ClaudeAPIError subclass instance.280    """281    stderr_lower = stderr.lower()282283    # Check for rate limiting284    if "rate limit" in stderr_lower or "429" in stderr_lower:285        return RateLimitError(stderr)286287    # Check for model not found288    if "model" in stderr_lower and ("not found" in stderr_lower or "invalid" in stderr_lower):289        # Try to extract model name290        return ClaudeAPIError(f"Model error: {stderr}", stderr, return_code)291292    # Check for CLI not installed293    if return_code == 127 or "command not found" in stderr_lower:294        return CLINotFoundError()295296    # Check for network errors297    if "network" in stderr_lower or "connection" in stderr_lower or "timeout" in stderr_lower:298        return ClaudeAPIError(f"Network error: {stderr}", stderr, return_code)299300    # Default to generic API error301    return ClaudeAPIError(f"Claude CLI failed: {stderr}", stderr, return_code)302