"""
Common error handling utilities for TimeLooker.
"""
import logging
from functools import wraps
from typing import Any, Callable, Dict, Optional
from fastapi import HTTPException, status
def log_exceptions(logger: logging.Logger = None):
"""
Decorator to log exceptions with context.
Args:
logger: Logger instance to use (defaults to module logger)
"""
def decorator(func: Callable) -> Callable:
@wraps(func)
def wrapper(*args, **kwargs):
try:
return func(*args, **kwargs)
except Exception as e:
log = logger or logging.getLogger(func.__module__)
log.error(f"Error in {func.__name__}: {e}", exc_info=True)
raise
return wrapper
return decorator
def log_async_exceptions(logger: logging.Logger = None):
"""
Decorator to log exceptions in async functions.
Args:
logger: Logger instance to use (defaults to module logger)
"""
def decorator(func: Callable) -> Callable:
@wraps(func)
async def wrapper(*args, **kwargs):
try:
return await func(*args, **kwargs)
except Exception as e:
log = logger or logging.getLogger(func.__module__)
log.error(f"Error in {func.__name__}: {e}", exc_info=True)
raise
return wrapper
return decorator
def create_http_error(
status_code: int,
message: str,
details: Optional[Dict[str, Any]] = None
) -> HTTPException:
"""
Create a standardized HTTP exception.
Args:
status_code: HTTP status code
message: Error message
details: Additional error details
Returns:
HTTPException with standardized format
"""
detail = {"message": message}
if details:
detail.update(details)
return HTTPException(status_code=status_code, detail=detail)
def handle_database_error(e: Exception, operation: str) -> HTTPException:
"""
Handle database errors with consistent formatting.
Args:
e: The exception that occurred
operation: Description of the operation that failed
Returns:
HTTPException with appropriate status and message
"""
error_msg = f"Database error during {operation}: {str(e)}"
return create_http_error(
status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
message=f"Failed to {operation}",
details={"error": str(e)}
)
def handle_validation_error(e: Exception, field: str = None) -> HTTPException:
"""
Handle validation errors with consistent formatting.
Args:
e: The exception that occurred
field: The field that failed validation (optional)
Returns:
HTTPException with appropriate status and message
"""
message = f"Validation error"
if field:
message += f" for field '{field}'"
return create_http_error(
status_code=status.HTTP_400_BAD_REQUEST,
message=message,
details={"error": str(e)}
)