Sistema de errores
Gestión Civis gestiona los errores de negocio mediante una excepción
aplicativa única (AppException) y un manejador global que la convierte en
una respuesta JSON homogénea. Cada módulo define su catálogo de errores con
códigos canónicos.
Regla del proyecto
Usar siempre raise AppException(...) (a través del catálogo errors.py del
módulo). Nunca devolver el error con return jsonify({"error": ...}).
Componentes
Definidos en app/core/exceptions.py.
ErrorSource
Captura automática del punto de origen del error.
@dataclass
class ErrorSource:
file: str # archivo donde se lanzó
line: int # número de línea
fn: str # función
AppError
Estructura de datos del error.
@dataclass
class AppError:
code: str # código canónico (ej. "REG-300")
message: str # mensaje para el usuario
source: Optional[ErrorSource] # contexto de origen
detail: Optional[Dict] # datos adicionales (severity, campos…)
http_status: int = 400 # código HTTP
AppException
Excepción que se lanza desde el código de negocio.
class AppException(Exception):
def __init__(self, code, message, *, http_status=400, detail=None, source_stack_level=2):
self.app_error = AppError(
code=code, message=message, http_status=http_status,
detail=detail, source=build_source(stack_level=source_stack_level),
)
- No produce la respuesta HTTP por sí misma: solo transporta el error.
- Captura automáticamente archivo, línea y función de origen.
Manejador global
Registrado en la app factory (app/__init__.py):
@app.errorhandler(AppException)
def handle_app_exception(error: AppException):
ae = error.app_error
payload = {
"error": {
"code": ae.code,
"message": ae.message,
"source": {"file": ae.source.file, "line": ae.source.line, "fn": ae.source.fn}
if ae.source else None,
"detail": ae.detail,
}
}
return jsonify(payload), ae.http_status
Formato de respuesta de error
{
"error": {
"code": "REG-300",
"message": "El registro no admite esta operación en su estado actual.",
"source": { "file": ".../registro/routes.py", "line": 870, "fn": "anular_registro" },
"detail": { "severity": "warning", "estado": "ANULADO" }
}
}
Otros manejadores
La factoría también gestiona RequestEntityTooLarge (subida > 10 MB → 413
con un mensaje en español).
Catálogos de errores por módulo
Cada módulo define errors.py con códigos agrupados por rango. El patrón:
cada error es un staticmethod que devuelve una AppException lista para
lanzar.
# app/modules/registro/servicios/errors.py (resumen)
class RegistroErrors:
@staticmethod
def REG_003():
return AppException("REG-003", "El extracto supera los 240 caracteres.",
http_status=400, detail={"severity": "warning"})
Uso en el handler:
Convención de rangos (ejemplo: módulo Registro)
| Rango | Categoría |
|---|---|
REG-0xx |
Validación de entrada / formato. |
REG-1xx |
Numeración / contador / hash-chain. |
REG-2xx |
Adjuntos (tamaño, hash, antivirus). |
REG-3xx |
Estado / transiciones. |
REG-4xx |
Asignación / expediente-almacén / traspaso UD. |
REG-5xx |
Oficinas. |
REG-6xx |
SIR. |
REG-7xx |
Sede ciudadana. |
REG-9xx |
Genéricos / no encontrado. |
Prefijo por módulo
El prefijo del código identifica el módulo (REG-, DOC-, PRES-,
TES-, REC-, CONT-…), lo que facilita localizar el origen del error.