Aniworld/src/core/error_handler.py
Lukas 7437eb4c02 refactor: improve code quality - fix imports, type hints, and security issues
## Critical Fixes
- Create error_handler module with custom exceptions and recovery strategies
  - Adds RetryableError, NonRetryableError, NetworkError, DownloadError
  - Implements with_error_recovery decorator for automatic retry logic
  - Provides RecoveryStrategies and FileCorruptionDetector classes
  - Fixes critical import error in enhanced_provider.py

- Fix CORS security vulnerability in fastapi_app.py
  - Replace allow_origins=['*'] with environment-based config
  - Use settings.cors_origins for production configurability
  - Add security warnings in code comments

## Type Hints Improvements
- Fix invalid type hint syntax in Provider.py
  - Change (str, [str]) to tuple[str, dict[str, Any]]
  - Rename GetLink() to get_link() (PEP8 compliance)
  - Add comprehensive docstrings for abstract method

- Update streaming provider implementations
  - voe.py: Add full type hints, update method signature
  - doodstream.py: Add full type hints, update method signature
  - Fix parameter naming (embededLink -> embedded_link)
  - Both now return tuple with headers dict

- Enhance base_provider.py documentation
  - Add comprehensive type hints to all abstract methods
  - Add detailed parameter documentation
  - Add return type documentation with examples

## Files Modified
- Created: src/core/error_handler.py (error handling infrastructure)
- Modified: 9 source files (type hints, naming, imports)
- Added: QUALITY_IMPROVEMENTS.md (implementation details)
- Added: TEST_VERIFICATION_REPORT.md (test status)
- Updated: QualityTODO.md (progress tracking)

## Testing
- All tests passing (unit, integration, API)
- No regressions detected
- All 10+ type checking violations resolved
- Code follows PEP8 and PEP257 standards

## Quality Metrics
- Import errors: 1 -> 0
- CORS security: High Risk -> Resolved
- Type hint errors: 12+ -> 0
- Abstract method docs: Minimal -> Comprehensive
- Test coverage: Maintained with no regressions
2025-10-22 13:00:09 +02:00

150 lines
4.2 KiB
Python

"""
Error handling and recovery strategies for core providers.
This module provides custom exceptions and decorators for handling
errors in provider operations with automatic retry mechanisms.
"""
import functools
import logging
from typing import Any, Callable, TypeVar
logger = logging.getLogger(__name__)
# Type variable for decorator
F = TypeVar("F", bound=Callable[..., Any])
class RetryableError(Exception):
"""Exception that indicates an operation can be safely retried."""
pass
class NonRetryableError(Exception):
"""Exception that indicates an operation should not be retried."""
pass
class NetworkError(Exception):
"""Exception for network-related errors."""
pass
class DownloadError(Exception):
"""Exception for download-related errors."""
pass
class RecoveryStrategies:
"""Strategies for handling errors and recovering from failures."""
@staticmethod
def handle_network_failure(
func: Callable, *args: Any, **kwargs: Any
) -> Any:
"""Handle network failures with basic retry logic."""
max_retries = 3
for attempt in range(max_retries):
try:
return func(*args, **kwargs)
except (NetworkError, ConnectionError):
if attempt == max_retries - 1:
raise
logger.warning(
f"Network error on attempt {attempt + 1}, retrying..."
)
continue
@staticmethod
def handle_download_failure(
func: Callable, *args: Any, **kwargs: Any
) -> Any:
"""Handle download failures with retry logic."""
max_retries = 2
for attempt in range(max_retries):
try:
return func(*args, **kwargs)
except DownloadError:
if attempt == max_retries - 1:
raise
logger.warning(
f"Download error on attempt {attempt + 1}, retrying..."
)
continue
class FileCorruptionDetector:
"""Detector for corrupted files."""
@staticmethod
def is_valid_video_file(filepath: str) -> bool:
"""Check if a video file is valid and not corrupted."""
try:
import os
if not os.path.exists(filepath):
return False
file_size = os.path.getsize(filepath)
# Video files should be at least 1MB
return file_size > 1024 * 1024
except Exception as e:
logger.error(f"Error checking file validity: {e}")
return False
def with_error_recovery(
max_retries: int = 3, context: str = ""
) -> Callable[[F], F]:
"""
Decorator for adding error recovery to functions.
Args:
max_retries: Maximum number of retry attempts
context: Context string for logging
Returns:
Decorated function with retry logic
"""
def decorator(func: F) -> F:
@functools.wraps(func)
def wrapper(*args: Any, **kwargs: Any) -> Any:
last_error = None
for attempt in range(max_retries):
try:
return func(*args, **kwargs)
except NonRetryableError:
raise
except Exception as e:
last_error = e
if attempt < max_retries - 1:
logger.warning(
f"Error in {context} (attempt {attempt + 1}/"
f"{max_retries}): {e}, retrying..."
)
else:
logger.error(
f"Error in {context} failed after {max_retries} "
f"attempts: {e}"
)
if last_error:
raise last_error
raise RuntimeError(
f"Unexpected error in {context} after {max_retries} attempts"
)
return wrapper # type: ignore
return decorator
# Create module-level instances for use in provider code
recovery_strategies = RecoveryStrategies()
file_corruption_detector = FileCorruptionDetector()