Files
HCFS/hcfs-python/hcfs/sdk/exceptions.py
2025-07-30 09:34:16 +10:00

184 lines
6.2 KiB
Python

"""
HCFS SDK Exception Classes
Comprehensive exception hierarchy for error handling.
"""
from typing import Optional, Dict, Any
class HCFSError(Exception):
"""Base exception for all HCFS SDK errors."""
def __init__(self, message: str, error_code: Optional[str] = None, details: Optional[Dict[str, Any]] = None):
super().__init__(message)
self.message = message
self.error_code = error_code
self.details = details or {}
def __str__(self) -> str:
if self.error_code:
return f"[{self.error_code}] {self.message}"
return self.message
def to_dict(self) -> Dict[str, Any]:
"""Convert exception to dictionary for serialization."""
return {
"type": self.__class__.__name__,
"message": self.message,
"error_code": self.error_code,
"details": self.details
}
class HCFSConnectionError(HCFSError):
"""Raised when connection to HCFS API fails."""
def __init__(self, message: str = "Failed to connect to HCFS API", **kwargs):
super().__init__(message, error_code="CONNECTION_FAILED", **kwargs)
class HCFSAuthenticationError(HCFSError):
"""Raised when authentication fails."""
def __init__(self, message: str = "Authentication failed", **kwargs):
super().__init__(message, error_code="AUTH_FAILED", **kwargs)
class HCFSAuthorizationError(HCFSError):
"""Raised when user lacks permissions for an operation."""
def __init__(self, message: str = "Insufficient permissions", **kwargs):
super().__init__(message, error_code="INSUFFICIENT_PERMISSIONS", **kwargs)
class HCFSNotFoundError(HCFSError):
"""Raised when a requested resource is not found."""
def __init__(self, resource_type: str = "Resource", resource_id: str = "", **kwargs):
message = f"{resource_type} not found"
if resource_id:
message += f": {resource_id}"
super().__init__(message, error_code="NOT_FOUND", **kwargs)
class HCFSValidationError(HCFSError):
"""Raised when request validation fails."""
def __init__(self, message: str = "Request validation failed", validation_errors: Optional[list] = None, **kwargs):
super().__init__(message, error_code="VALIDATION_FAILED", **kwargs)
self.validation_errors = validation_errors or []
def to_dict(self) -> Dict[str, Any]:
result = super().to_dict()
result["validation_errors"] = self.validation_errors
return result
class HCFSRateLimitError(HCFSError):
"""Raised when rate limit is exceeded."""
def __init__(self, retry_after: Optional[int] = None, **kwargs):
message = "Rate limit exceeded"
if retry_after:
message += f". Retry after {retry_after} seconds"
super().__init__(message, error_code="RATE_LIMIT_EXCEEDED", **kwargs)
self.retry_after = retry_after
class HCFSServerError(HCFSError):
"""Raised for server-side errors (5xx status codes)."""
def __init__(self, message: str = "Internal server error", status_code: Optional[int] = None, **kwargs):
super().__init__(message, error_code="SERVER_ERROR", **kwargs)
self.status_code = status_code
class HCFSTimeoutError(HCFSError):
"""Raised when a request times out."""
def __init__(self, operation: str = "Request", timeout_seconds: Optional[float] = None, **kwargs):
message = f"{operation} timed out"
if timeout_seconds:
message += f" after {timeout_seconds}s"
super().__init__(message, error_code="TIMEOUT", **kwargs)
self.timeout_seconds = timeout_seconds
class HCFSCacheError(HCFSError):
"""Raised for cache-related errors."""
def __init__(self, message: str = "Cache operation failed", **kwargs):
super().__init__(message, error_code="CACHE_ERROR", **kwargs)
class HCFSBatchError(HCFSError):
"""Raised for batch operation errors."""
def __init__(self, message: str = "Batch operation failed", failed_items: Optional[list] = None, **kwargs):
super().__init__(message, error_code="BATCH_ERROR", **kwargs)
self.failed_items = failed_items or []
def to_dict(self) -> Dict[str, Any]:
result = super().to_dict()
result["failed_items"] = self.failed_items
return result
class HCFSStreamError(HCFSError):
"""Raised for streaming/WebSocket errors."""
def __init__(self, message: str = "Stream operation failed", **kwargs):
super().__init__(message, error_code="STREAM_ERROR", **kwargs)
class HCFSSearchError(HCFSError):
"""Raised for search operation errors."""
def __init__(self, query: str = "", search_type: str = "", **kwargs):
message = f"Search failed"
if search_type:
message += f" ({search_type})"
if query:
message += f": '{query}'"
super().__init__(message, error_code="SEARCH_ERROR", **kwargs)
self.query = query
self.search_type = search_type
def handle_api_error(response) -> None:
"""
Convert HTTP response errors to appropriate HCFS exceptions.
Args:
response: HTTP response object
Raises:
Appropriate HCFSError subclass based on status code
"""
status_code = response.status_code
try:
error_data = response.json() if response.content else {}
except Exception:
error_data = {}
error_message = error_data.get("error", "Unknown error")
error_details = error_data.get("error_details", [])
if status_code == 400:
raise HCFSValidationError(error_message, validation_errors=error_details)
elif status_code == 401:
raise HCFSAuthenticationError(error_message)
elif status_code == 403:
raise HCFSAuthorizationError(error_message)
elif status_code == 404:
raise HCFSNotFoundError("Resource", error_message)
elif status_code == 429:
retry_after = response.headers.get("Retry-After")
retry_after = int(retry_after) if retry_after else None
raise HCFSRateLimitError(retry_after=retry_after)
elif 500 <= status_code < 600:
raise HCFSServerError(error_message, status_code=status_code)
else:
raise HCFSError(f"HTTP {status_code}: {error_message}")