fix test and add doc

This commit is contained in:
2025-10-22 11:30:04 +02:00
parent 1637835fe6
commit 9692dfc63b
13 changed files with 3562 additions and 146 deletions

View 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,
)

View File

@@ -0,0 +1,35 @@
"""
Exceptions module for Aniworld server API.
This module provides custom exception classes for the web API layer
with proper HTTP status code mappings.
"""
from src.server.exceptions import (
AniWorldAPIException,
AuthenticationError,
AuthorizationError,
ConfigurationError,
ConflictError,
DatabaseError,
DownloadError,
NotFoundError,
ProviderError,
RateLimitError,
ServerError,
ValidationError,
)
__all__ = [
"AniWorldAPIException",
"AuthenticationError",
"AuthorizationError",
"ValidationError",
"NotFoundError",
"ConflictError",
"RateLimitError",
"ServerError",
"DownloadError",
"ConfigurationError",
"ProviderError",
"DatabaseError",
]