Spaces:
Paused
Paused
| """ | |
| Custom Exception Classes for Flare Platform | |
| """ | |
| from typing import Optional, Dict, Any | |
| from datetime import datetime | |
| class FlareException(Exception): | |
| """Base exception for Flare""" | |
| def __init__(self, message: str, details: Optional[Dict[str, Any]] = None): | |
| self.message = message | |
| self.details = details or {} | |
| self.timestamp = datetime.utcnow() | |
| super().__init__(self.message) | |
| def to_dict(self) -> Dict[str, Any]: | |
| """Convert exception to dictionary""" | |
| return { | |
| "error": self.__class__.__name__, | |
| "message": self.message, | |
| "details": self.details, | |
| "timestamp": self.timestamp.isoformat() | |
| } | |
| def to_http_detail(self) -> Dict[str, Any]: | |
| """Convert to HTTP response detail""" | |
| return { | |
| "detail": self.message, | |
| "error_type": self.__class__.__name__.lower().replace('error', ''), | |
| **self.details | |
| } | |
| class RaceConditionError(FlareException): | |
| """Raised when a race condition is detected during concurrent updates""" | |
| def __init__( | |
| self, | |
| message: str, | |
| current_user: Optional[str] = None, | |
| last_update_user: Optional[str] = None, | |
| last_update_date: Optional[str] = None, | |
| entity_type: Optional[str] = None, | |
| entity_id: Optional[Any] = None | |
| ): | |
| details = { | |
| "current_user": current_user, | |
| "last_update_user": last_update_user, | |
| "last_update_date": last_update_date, | |
| "entity_type": entity_type, | |
| "entity_id": entity_id, | |
| "action": "Please reload the data and try again" | |
| } | |
| super().__init__(message, details) | |
| self.current_user = current_user | |
| self.last_update_user = last_update_user | |
| self.last_update_date = last_update_date | |
| def to_http_detail(self) -> Dict[str, Any]: | |
| """Convert to HTTPException detail format with proper serialization""" | |
| return { | |
| "message": self.message, | |
| "last_update_user": self.last_update_user, | |
| "last_update_date": self.last_update_date.isoformat() if isinstance(self.last_update_date, datetime) else self.last_update_date, | |
| "type": "race_condition" | |
| } | |
| class ConfigurationError(FlareException): | |
| """Raised when there's a configuration issue""" | |
| def __init__(self, message: str, config_key: Optional[str] = None): | |
| details = {"config_key": config_key} if config_key else {} | |
| super().__init__(message, details) | |
| class ValidationError(FlareException): | |
| """Raised when validation fails""" | |
| def __init__(self, message: str, field: Optional[str] = None, value: Any = None): | |
| details = {} | |
| if field: | |
| details["field"] = field | |
| if value is not None: | |
| details["value"] = str(value) | |
| super().__init__(message, details) | |
| class AuthenticationError(FlareException): | |
| """Raised when authentication fails""" | |
| def __init__(self, message: str = "Authentication failed"): | |
| super().__init__(message) | |
| class AuthorizationError(FlareException): | |
| """Raised when authorization fails""" | |
| def __init__(self, message: str = "Insufficient permissions", required_permission: Optional[str] = None): | |
| details = {"required_permission": required_permission} if required_permission else {} | |
| super().__init__(message, details) | |
| class SessionError(FlareException): | |
| """Raised when there's a session-related error""" | |
| def __init__(self, message: str, session_id: Optional[str] = None): | |
| details = {"session_id": session_id} if session_id else {} | |
| super().__init__(message, details) | |
| class ProviderError(FlareException): | |
| """Raised when a provider (LLM, TTS, STT) fails""" | |
| def __init__(self, message: str, provider_type: str, provider_name: str, original_error: Optional[str] = None): | |
| details = { | |
| "provider_type": provider_type, | |
| "provider_name": provider_name, | |
| "original_error": original_error | |
| } | |
| super().__init__(message, details) | |
| class APICallError(FlareException): | |
| """Raised when an external API call fails""" | |
| def __init__( | |
| self, | |
| message: str, | |
| api_name: str, | |
| status_code: Optional[int] = None, | |
| response_body: Optional[str] = None | |
| ): | |
| details = { | |
| "api_name": api_name, | |
| "status_code": status_code, | |
| "response_body": response_body | |
| } | |
| super().__init__(message, details) | |
| class WebSocketError(FlareException): | |
| """Raised when WebSocket operations fail""" | |
| def __init__(self, message: str, session_id: Optional[str] = None, state: Optional[str] = None): | |
| details = { | |
| "session_id": session_id, | |
| "state": state | |
| } | |
| super().__init__(message, details) | |
| class ResourceNotFoundError(FlareException): | |
| """Raised when a requested resource is not found""" | |
| def __init__(self, resource_type: str, resource_id: Any): | |
| message = f"{resource_type} not found: {resource_id}" | |
| details = { | |
| "resource_type": resource_type, | |
| "resource_id": str(resource_id) | |
| } | |
| super().__init__(message, details) | |
| class DuplicateResourceError(FlareException): | |
| """Raised when attempting to create a duplicate resource""" | |
| def __init__(self, resource_type: str, identifier: str): | |
| message = f"{resource_type} already exists: {identifier}" | |
| details = { | |
| "resource_type": resource_type, | |
| "identifier": identifier | |
| } | |
| super().__init__(message, details) | |
| # Error response formatters | |
| def format_error_response(error: Exception, request_id: Optional[str] = None) -> Dict[str, Any]: | |
| """Format any exception into a standardized error response""" | |
| if isinstance(error, FlareException): | |
| response = error.to_dict() | |
| else: | |
| # Generic error | |
| response = { | |
| "error": error.__class__.__name__, | |
| "message": str(error), | |
| "details": {}, | |
| "timestamp": datetime.utcnow().isoformat() | |
| } | |
| if request_id: | |
| response["request_id"] = request_id | |
| return response | |
| def get_http_status_code(error: Exception) -> int: | |
| """Get appropriate HTTP status code for an exception""" | |
| status_map = { | |
| ValidationError: 422, | |
| AuthenticationError: 401, | |
| AuthorizationError: 403, | |
| ResourceNotFoundError: 404, | |
| DuplicateResourceError: 409, | |
| RaceConditionError: 409, | |
| ConfigurationError: 500, | |
| ProviderError: 503, | |
| APICallError: 502, | |
| WebSocketError: 500, | |
| SessionError: 400 | |
| } | |
| for error_class, status_code in status_map.items(): | |
| if isinstance(error, error_class): | |
| return status_code | |
| # Default to 500 for unknown errors | |
| return 500 | |