fix test and add doc
This commit is contained in:
255
src/server/exceptions/__init__.py
Normal file
255
src/server/exceptions/__init__.py
Normal file
@@ -0,0 +1,255 @@
|
||||
"""
|
||||
Custom exception classes for Aniworld API layer.
|
||||
|
||||
This module defines exception hierarchy for the web API with proper
|
||||
HTTP status code mappings and error handling.
|
||||
"""
|
||||
from typing import Any, Dict, Optional
|
||||
|
||||
|
||||
class AniWorldAPIException(Exception):
|
||||
"""
|
||||
Base exception for Aniworld API.
|
||||
|
||||
All API-specific exceptions inherit from this class.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
message: str,
|
||||
status_code: int = 500,
|
||||
error_code: Optional[str] = None,
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
):
|
||||
"""
|
||||
Initialize API exception.
|
||||
|
||||
Args:
|
||||
message: Human-readable error message
|
||||
status_code: HTTP status code for response
|
||||
error_code: Machine-readable error identifier
|
||||
details: Additional error details and context
|
||||
"""
|
||||
self.message = message
|
||||
self.status_code = status_code
|
||||
self.error_code = error_code or self.__class__.__name__
|
||||
self.details = details or {}
|
||||
super().__init__(self.message)
|
||||
|
||||
def to_dict(self) -> Dict[str, Any]:
|
||||
"""
|
||||
Convert exception to dictionary for JSON response.
|
||||
|
||||
Returns:
|
||||
Dictionary containing error information
|
||||
"""
|
||||
return {
|
||||
"error": self.error_code,
|
||||
"message": self.message,
|
||||
"details": self.details,
|
||||
}
|
||||
|
||||
|
||||
class AuthenticationError(AniWorldAPIException):
|
||||
"""Exception raised when authentication fails."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Authentication failed",
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
):
|
||||
"""Initialize authentication error."""
|
||||
super().__init__(
|
||||
message=message,
|
||||
status_code=401,
|
||||
error_code="AUTHENTICATION_ERROR",
|
||||
details=details,
|
||||
)
|
||||
|
||||
|
||||
class AuthorizationError(AniWorldAPIException):
|
||||
"""Exception raised when user lacks required permissions."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Insufficient permissions",
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
):
|
||||
"""Initialize authorization error."""
|
||||
super().__init__(
|
||||
message=message,
|
||||
status_code=403,
|
||||
error_code="AUTHORIZATION_ERROR",
|
||||
details=details,
|
||||
)
|
||||
|
||||
|
||||
class ValidationError(AniWorldAPIException):
|
||||
"""Exception raised when request validation fails."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Request validation failed",
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
):
|
||||
"""Initialize validation error."""
|
||||
super().__init__(
|
||||
message=message,
|
||||
status_code=422,
|
||||
error_code="VALIDATION_ERROR",
|
||||
details=details,
|
||||
)
|
||||
|
||||
|
||||
class NotFoundError(AniWorldAPIException):
|
||||
"""Exception raised when resource is not found."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Resource not found",
|
||||
resource_type: Optional[str] = None,
|
||||
resource_id: Optional[Any] = None,
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
):
|
||||
"""Initialize not found error."""
|
||||
if details is None:
|
||||
details = {}
|
||||
if resource_type:
|
||||
details["resource_type"] = resource_type
|
||||
if resource_id:
|
||||
details["resource_id"] = resource_id
|
||||
|
||||
super().__init__(
|
||||
message=message,
|
||||
status_code=404,
|
||||
error_code="NOT_FOUND",
|
||||
details=details,
|
||||
)
|
||||
|
||||
|
||||
class ConflictError(AniWorldAPIException):
|
||||
"""Exception raised when resource conflict occurs."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Resource conflict",
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
):
|
||||
"""Initialize conflict error."""
|
||||
super().__init__(
|
||||
message=message,
|
||||
status_code=409,
|
||||
error_code="CONFLICT",
|
||||
details=details,
|
||||
)
|
||||
|
||||
|
||||
class RateLimitError(AniWorldAPIException):
|
||||
"""Exception raised when rate limit is exceeded."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Rate limit exceeded",
|
||||
retry_after: Optional[int] = None,
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
):
|
||||
"""Initialize rate limit error."""
|
||||
if details is None:
|
||||
details = {}
|
||||
if retry_after:
|
||||
details["retry_after"] = retry_after
|
||||
|
||||
super().__init__(
|
||||
message=message,
|
||||
status_code=429,
|
||||
error_code="RATE_LIMIT_EXCEEDED",
|
||||
details=details,
|
||||
)
|
||||
|
||||
|
||||
class ServerError(AniWorldAPIException):
|
||||
"""Exception raised for internal server errors."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Internal server error",
|
||||
error_code: str = "INTERNAL_SERVER_ERROR",
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
):
|
||||
"""Initialize server error."""
|
||||
super().__init__(
|
||||
message=message,
|
||||
status_code=500,
|
||||
error_code=error_code,
|
||||
details=details,
|
||||
)
|
||||
|
||||
|
||||
class DownloadError(ServerError):
|
||||
"""Exception raised when download operation fails."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Download failed",
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
):
|
||||
"""Initialize download error."""
|
||||
super().__init__(
|
||||
message=message,
|
||||
error_code="DOWNLOAD_ERROR",
|
||||
details=details,
|
||||
)
|
||||
|
||||
|
||||
class ConfigurationError(ServerError):
|
||||
"""Exception raised when configuration is invalid."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Configuration error",
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
):
|
||||
"""Initialize configuration error."""
|
||||
super().__init__(
|
||||
message=message,
|
||||
error_code="CONFIGURATION_ERROR",
|
||||
details=details,
|
||||
)
|
||||
|
||||
|
||||
class ProviderError(ServerError):
|
||||
"""Exception raised when provider operation fails."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Provider error",
|
||||
provider_name: Optional[str] = None,
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
):
|
||||
"""Initialize provider error."""
|
||||
if details is None:
|
||||
details = {}
|
||||
if provider_name:
|
||||
details["provider"] = provider_name
|
||||
|
||||
super().__init__(
|
||||
message=message,
|
||||
error_code="PROVIDER_ERROR",
|
||||
details=details,
|
||||
)
|
||||
|
||||
|
||||
class DatabaseError(ServerError):
|
||||
"""Exception raised when database operation fails."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
message: str = "Database error",
|
||||
details: Optional[Dict[str, Any]] = None,
|
||||
):
|
||||
"""Initialize database error."""
|
||||
super().__init__(
|
||||
message=message,
|
||||
error_code="DATABASE_ERROR",
|
||||
details=details,
|
||||
)
|
||||
Reference in New Issue
Block a user