Source code for scitex_logging._errors

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# Timestamp: "2025-12-21"
# File: /home/ywatanabe/proj/scitex-code/src/scitex/logging/_errors.py

"""Error classes for SciTeX.

All SciTeX exceptions are defined here for unified error handling.
Re-exported from scitex.logging for backwards compatibility.

Usage:
    from scitex_logging import SciTeXError, SaveError, LoadError
    # or (backwards compatible)
    from scitex_logging import SciTeXError, SaveError, LoadError
"""

from typing import Optional, Union

# =============================================================================
# Base Errors
# =============================================================================


[docs] class SciTeXError(Exception): """Base Exception class for all SciTeX errors."""
[docs] def __init__( self, message: str, context: Optional[dict] = None, suggestion: Optional[str] = None, ): """Initialize SciTeX error with detailed information. Parameters ---------- message : str The error message context : dict, optional Additional context information (e.g., file paths, variable values) suggestion : str, optional Suggested fix or action """ self.message = message self.context = context or {} self.suggestion = suggestion # Build the full error message error_parts = [f"SciTeX Error: {message}"] if context: error_parts.append("\nContext:") for key, value in context.items(): error_parts.append(f" {key}: {value}") if suggestion: error_parts.append(f"\nSuggestion: {suggestion}") super().__init__("\n".join(error_parts))
# ============================================================================= # Configuration Errors # =============================================================================
[docs] class ConfigurationError(SciTeXError): """Raised when there are issues with SciTeX configuration.""" pass
[docs] class ConfigFileNotFoundError(ConfigurationError): """Raised when a required configuration file is not found.""" def __init__(self, filepath: str): super().__init__( f"Configuration file not found: {filepath}", context={"filepath": filepath}, suggestion="Ensure the configuration file exists in ./config/ directory", )
[docs] class ConfigKeyError(ConfigurationError): """Raised when a required configuration key is missing.""" def __init__(self, key: str, available_keys: Optional[list] = None): context = {"missing_key": key} if available_keys: context["available_keys"] = available_keys super().__init__( f"Configuration key '{key}' not found", context=context, suggestion=f"Add '{key}' to your configuration file or check for typos", )
# ============================================================================= # IO Errors # =============================================================================
[docs] class IOError(SciTeXError): """Base class for input/output related errors.""" pass
[docs] class FileFormatError(IOError): """Raised when file format is not supported or incorrect.""" def __init__( self, filepath: str, expected_format: Optional[str] = None, actual_format: Optional[str] = None, ): context = {"filepath": filepath} if expected_format: context["expected_format"] = expected_format if actual_format: context["actual_format"] = actual_format message = f"File format error for: {filepath}" if expected_format and actual_format: message += f" (expected: {expected_format}, got: {actual_format})" super().__init__( message, context=context, suggestion="Check the file extension and content format", )
[docs] class SaveError(IOError): """Raised when saving data fails.""" def __init__(self, filepath: str, reason: str): super().__init__( f"Failed to save to {filepath}: {reason}", context={"filepath": filepath, "reason": reason}, suggestion="Check file permissions and disk space", )
[docs] class LoadError(IOError): """Raised when loading data fails.""" def __init__(self, filepath: str, reason: str): super().__init__( f"Failed to load from {filepath}: {reason}", context={"filepath": filepath, "reason": reason}, suggestion="Verify the file exists and is not corrupted", )
# ============================================================================= # Scholar Module Errors # =============================================================================
[docs] class ScholarError(SciTeXError): """Base class for scholar module errors.""" pass
[docs] class SearchError(ScholarError): """Raised when paper search fails.""" def __init__(self, query: str, source: str, reason: str): super().__init__( f"Search failed for query '{query}' on {source}", context={"query": query, "source": source, "reason": reason}, suggestion="Check your internet connection and API keys", )
[docs] class EnrichmentError(ScholarError): """Raised when paper enrichment fails.""" def __init__(self, paper_title: str, reason: str): super().__init__( f"Failed to enrich paper: {paper_title}", context={"paper_title": paper_title, "reason": reason}, suggestion="Verify journal information is available", )
[docs] class PDFDownloadError(ScholarError): """Raised when PDF download fails.""" def __init__(self, url: str, reason: str): super().__init__( f"Failed to download PDF from {url}", context={"url": url, "reason": reason}, suggestion="Check if the paper is open access", )
[docs] class DOIResolutionError(ScholarError): """Raised when DOI resolution fails.""" def __init__(self, doi: str, reason: str): super().__init__( f"Failed to resolve DOI: {doi}", context={"doi": doi, "reason": reason}, suggestion="Verify the DOI is correct and try again", )
[docs] class PDFExtractionError(ScholarError): """Raised when PDF text extraction fails.""" def __init__(self, filepath: str, reason: str): super().__init__( f"Failed to extract text from PDF: {filepath}", context={"filepath": filepath, "reason": reason}, suggestion="Ensure the PDF is not corrupted or encrypted", )
[docs] class BibTeXEnrichmentError(ScholarError): """Raised when BibTeX enrichment fails.""" def __init__(self, bibtex_file: str, reason: str): super().__init__( f"Failed to enrich BibTeX file: {bibtex_file}", context={"bibtex_file": bibtex_file, "reason": reason}, suggestion="Check the BibTeX format and ensure all entries are valid", )
[docs] class TranslatorError(ScholarError): """Raised when Zotero translator operations fail.""" def __init__(self, translator_name: str, reason: str): super().__init__( f"Translator error in {translator_name}: {reason}", context={"translator": translator_name, "reason": reason}, suggestion="Check translator compatibility and JavaScript environment", )
[docs] class AuthenticationError(ScholarError): """Raised when authentication fails.""" def __init__(self, provider: str, reason: str = ""): super().__init__( f"Authentication failed for {provider}: {reason}", context={"provider": provider, "reason": reason}, suggestion="Check your credentials and authentication settings", )
# ============================================================================= # Plotting Errors # =============================================================================
[docs] class PlottingError(SciTeXError): """Base class for plotting-related errors.""" pass
[docs] class FigureNotFoundError(PlottingError): """Raised when attempting to operate on a non-existent figure.""" def __init__(self, fig_id: Union[int, str]): super().__init__( f"Figure {fig_id} not found", context={"figure_id": fig_id}, suggestion="Ensure the figure was created before attempting to save/modify it", )
[docs] class AxisError(PlottingError): """Raised when there are issues with plot axes.""" def __init__(self, message: str, axis_info: Optional[dict] = None): super().__init__( message, context={"axis_info": axis_info} if axis_info else None, suggestion="Check axis indices and subplot configuration", )
# ============================================================================= # Data Processing Errors # =============================================================================
[docs] class DataError(SciTeXError): """Base class for data processing errors.""" pass
[docs] class ShapeError(DataError): """Raised when data shapes are incompatible.""" def __init__(self, expected_shape: tuple, actual_shape: tuple, operation: str): super().__init__( f"Shape mismatch in {operation}", context={ "expected_shape": expected_shape, "actual_shape": actual_shape, "operation": operation, }, suggestion="Reshape or transpose your data to match expected dimensions", )
[docs] class DTypeError(DataError): """Raised when data types are incompatible.""" def __init__(self, expected_dtype: str, actual_dtype: str, operation: str): super().__init__( f"Data type mismatch in {operation}", context={ "expected_dtype": expected_dtype, "actual_dtype": actual_dtype, "operation": operation, }, suggestion=f"Convert data to {expected_dtype} using appropriate casting", )
# ============================================================================= # Path Errors # =============================================================================
[docs] class PathError(SciTeXError): """Base class for path-related errors.""" pass
[docs] class InvalidPathError(PathError): """Raised when a path is invalid or doesn't follow SciTeX conventions.""" def __init__(self, path: str, reason: str): super().__init__( f"Invalid path: {path}", context={"path": path, "reason": reason}, suggestion="Use relative paths starting with './' or '../'", )
[docs] class PathNotFoundError(PathError): """Raised when a required path doesn't exist.""" def __init__(self, path: str): super().__init__( f"Path not found: {path}", context={"path": path}, suggestion="Check if the path exists and is accessible", )
# ============================================================================= # Template Errors # =============================================================================
[docs] class TemplateError(SciTeXError): """Base class for template-related errors.""" pass
[docs] class TemplateViolationError(TemplateError): """Raised when SciTeX template is not followed.""" def __init__(self, filepath: str, violation: str): super().__init__( f"Template violation in {filepath}: {violation}", context={"filepath": filepath, "violation": violation}, suggestion="Follow the SciTeX template structure as defined in IMPORTANT-SCITEX-02-file-template.md", )
# ============================================================================= # Neural Network Errors # =============================================================================
[docs] class NNError(SciTeXError): """Base class for neural network module errors.""" pass
[docs] class ModelError(NNError): """Raised when there are issues with neural network models.""" def __init__(self, model_name: str, reason: str): super().__init__( f"Model error in {model_name}: {reason}", context={"model_name": model_name, "reason": reason}, )
# ============================================================================= # Statistics Errors # =============================================================================
[docs] class StatsError(SciTeXError): """Base class for statistics module errors.""" pass
[docs] class TestError(StatsError): """Raised when statistical tests fail.""" def __init__(self, test_name: str, reason: str): super().__init__( f"Statistical test '{test_name}' failed: {reason}", context={"test_name": test_name, "reason": reason}, )
# ============================================================================= # Validation Helpers # =============================================================================
[docs] def check_path(path: str) -> None: """Validate a path according to SciTeX conventions.""" if not isinstance(path, str): raise InvalidPathError(str(path), "Path must be a string") if not (path.startswith("./") or path.startswith("../")): raise InvalidPathError( path, "Path must be relative and start with './' or '../'" )
[docs] def check_file_exists(filepath: str) -> None: """Check if a file exists.""" import os if not os.path.exists(filepath): raise PathNotFoundError(filepath)
[docs] def check_shape_compatibility(shape1: tuple, shape2: tuple, operation: str) -> None: """Check if two shapes are compatible for an operation.""" if shape1 != shape2: raise ShapeError(shape1, shape2, operation)
__all__ = [ # Base errors "SciTeXError", # Configuration "ConfigurationError", "ConfigFileNotFoundError", "ConfigKeyError", # IO "IOError", "FileFormatError", "SaveError", "LoadError", # Scholar "ScholarError", "SearchError", "EnrichmentError", "PDFDownloadError", "DOIResolutionError", "PDFExtractionError", "BibTeXEnrichmentError", "TranslatorError", "AuthenticationError", # Plotting "PlottingError", "FigureNotFoundError", "AxisError", # Data "DataError", "ShapeError", "DTypeError", # Path "PathError", "InvalidPathError", "PathNotFoundError", # Template "TemplateError", "TemplateViolationError", # Neural Network "NNError", "ModelError", # Statistics "StatsError", "TestError", # Validation helpers "check_path", "check_file_exists", "check_shape_compatibility", ] # EOF