PARA.AI / api /utils /exceptions.py
caarleexx's picture
Rename api/exceptions.py to api/utils/exceptions.py
e219498 verified
raw
history blame
9.31 kB
"""
Exceções customizadas para para.AI API v3.0
Define hierarquia de exceções para tratamento de erros
"""
from typing import Optional, Dict, Any
class ParaAIException(Exception):
"""
Exceção base para todas as exceções customizadas do para.AI.
Todas as outras exceções devem herdar desta classe.
"""
def __init__(
self,
message: str,
details: Optional[Dict[str, Any]] = None,
status_code: int = 500
):
"""
Args:
message: Mensagem de erro principal
details: Dicionário com detalhes adicionais do erro
status_code: Código HTTP sugerido para este erro
"""
self.message = message
self.details = details or {}
self.status_code = status_code
super().__init__(self.message)
def to_dict(self) -> Dict[str, Any]:
"""Converte exceção para dicionário (útil para JSON responses)."""
return {
"error": self.__class__.__name__,
"message": self.message,
"details": self.details,
"status_code": self.status_code
}
def __str__(self) -> str:
"""String representation."""
if self.details:
return f"{self.message} | Details: {self.details}"
return self.message
# ============================================================================
# EXCEÇÕES DE DATABASE
# ============================================================================
class DatabaseException(ParaAIException):
"""Exceção genérica de banco de dados."""
def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):
super().__init__(message, details, status_code=500)
class DatabaseConnectionError(DatabaseException):
"""Erro de conexão com banco de dados."""
def __init__(self, message: str = "Falha ao conectar com banco de dados", details: Optional[Dict[str, Any]] = None):
super().__init__(message, details)
class RecordNotFoundError(DatabaseException):
"""Registro não encontrado no banco."""
def __init__(self, message: str = "Registro não encontrado", details: Optional[Dict[str, Any]] = None):
super().__init__(message, details)
self.status_code = 404
class DuplicateRecordError(DatabaseException):
"""Tentativa de inserir registro duplicado."""
def __init__(self, message: str = "Registro duplicado", details: Optional[Dict[str, Any]] = None):
super().__init__(message, details)
self.status_code = 409
# ============================================================================
# EXCEÇÕES DE LLM
# ============================================================================
class LLMException(ParaAIException):
"""Exceção genérica de LLM."""
def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):
super().__init__(message, details, status_code=500)
class LLMProviderNotAvailable(LLMException):
"""Provedor LLM não disponível."""
def __init__(self, provider: str, details: Optional[Dict[str, Any]] = None):
message = f"Provedor LLM '{provider}' não disponível ou não configurado"
super().__init__(message, details)
self.status_code = 503
class LLMAPIError(LLMException):
"""Erro na chamada da API do LLM."""
def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):
super().__init__(f"Erro na API do LLM: {message}", details)
class LLMTimeoutError(LLMException):
"""Timeout na chamada do LLM."""
def __init__(self, timeout: int, details: Optional[Dict[str, Any]] = None):
message = f"Timeout de {timeout}s excedido na chamada do LLM"
super().__init__(message, details)
self.status_code = 504
class LLMResponseParseError(LLMException):
"""Erro ao fazer parse da resposta do LLM."""
def __init__(self, message: str = "Falha ao processar resposta do LLM", details: Optional[Dict[str, Any]] = None):
super().__init__(message, details)
# ============================================================================
# EXCEÇÕES DE PROCESSAMENTO
# ============================================================================
class ProcessingException(ParaAIException):
"""Exceção genérica de processamento."""
def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):
super().__init__(message, details, status_code=500)
class ProcessorNotFoundError(ProcessingException):
"""Processador não encontrado."""
def __init__(self, processor_name: str, details: Optional[Dict[str, Any]] = None):
message = f"Processador '{processor_name}' não encontrado"
super().__init__(message, details)
self.status_code = 404
class ProcessingTimeoutError(ProcessingException):
"""Timeout no processamento."""
def __init__(self, timeout: int, details: Optional[Dict[str, Any]] = None):
message = f"Timeout de {timeout}s excedido no processamento"
super().__init__(message, details)
self.status_code = 504
class ValidationError(ProcessingException):
"""Erro de validação de dados."""
def __init__(self, message: str = "Dados inválidos", details: Optional[Dict[str, Any]] = None):
super().__init__(message, details)
self.status_code = 422
# ============================================================================
# EXCEÇÕES DE ARQUIVO
# ============================================================================
class FileException(ParaAIException):
"""Exceção genérica de arquivo."""
def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):
super().__init__(message, details, status_code=500)
class FileNotFoundError(FileException):
"""Arquivo não encontrado."""
def __init__(self, filepath: str, details: Optional[Dict[str, Any]] = None):
message = f"Arquivo não encontrado: {filepath}"
super().__init__(message, details)
self.status_code = 404
class FileUploadError(FileException):
"""Erro no upload de arquivo."""
def __init__(self, message: str = "Erro ao fazer upload do arquivo", details: Optional[Dict[str, Any]] = None):
super().__init__(message, details)
self.status_code = 400
class FileFormatError(FileException):
"""Formato de arquivo inválido."""
def __init__(self, message: str = "Formato de arquivo inválido", details: Optional[Dict[str, Any]] = None):
super().__init__(message, details)
self.status_code = 415
class FileSizeExceededError(FileException):
"""Tamanho de arquivo excedido."""
def __init__(self, size: int, max_size: int, details: Optional[Dict[str, Any]] = None):
message = f"Arquivo muito grande: {size} bytes (máximo: {max_size} bytes)"
super().__init__(message, details)
self.status_code = 413
# ============================================================================
# EXCEÇÕES DE CONFIGURAÇÃO
# ============================================================================
class ConfigurationError(ParaAIException):
"""Erro de configuração."""
def __init__(self, message: str, details: Optional[Dict[str, Any]] = None):
super().__init__(f"Erro de configuração: {message}", details)
self.status_code = 500
class MissingConfigurationError(ConfigurationError):
"""Configuração obrigatória ausente."""
def __init__(self, config_name: str, details: Optional[Dict[str, Any]] = None):
message = f"Configuração obrigatória ausente: {config_name}"
super().__init__(message, details)
# ============================================================================
# EXCEÇÕES DE AUTENTICAÇÃO/AUTORIZAÇÃO
# ============================================================================
class AuthenticationError(ParaAIException):
"""Erro de autenticação."""
def __init__(self, message: str = "Falha na autenticação", details: Optional[Dict[str, Any]] = None):
super().__init__(message, details)
self.status_code = 401
class AuthorizationError(ParaAIException):
"""Erro de autorização."""
def __init__(self, message: str = "Acesso negado", details: Optional[Dict[str, Any]] = None):
super().__init__(message, details)
self.status_code = 403
class InvalidAPIKeyError(AuthenticationError):
"""API Key inválida."""
def __init__(self, details: Optional[Dict[str, Any]] = None):
super().__init__("API Key inválida ou expirada", details)
# ============================================================================
# FUNÇÃO AUXILIAR
# ============================================================================
def handle_exception(exc: Exception) -> Dict[str, Any]:
"""
Converte qualquer exceção para dicionário padronizado.
Args:
exc: Exceção a ser convertida
Returns:
Dicionário com informações do erro
"""
if isinstance(exc, ParaAIException):
return exc.to_dict()
# Exceção genérica
return {
"error": exc.__class__.__name__,
"message": str(exc),
"details": {},
"status_code": 500
}