"""Common utilities.""" import logging import traceback from typing import Callable from flask import request, Response, make_response, render_template logger = logging.getLogger(__name__) def add_trace(exc: Exception, errobj: dict) -> dict: """Add the traceback to the error handling object.""" return { **errobj, "error-trace": "".join(traceback.format_exception(exc)) } def __status_code__(exc: Exception): """Fetch the error code for exceptions that have them.""" error_code_attributes = ( "code", "error_code", "errorcode", "status_code", "status_code") for attr in error_code_attributes: if hasattr(exc, attr): return getattr(exc, attr) return 500 def build_handler(description: str) -> Callable[[Exception], Response]: """Generic utility to build error handlers.""" def __handler__(exc: Exception) -> Response: """Handle the exception as appropriate for requests of different mimetypes.""" error = (exc.name if hasattr(exc, "name") else exc.__class__.__name__) status_code = __status_code__(exc) content_type = request.content_type if bool(content_type) and content_type.lower() == "application/json": return make_response(( add_trace( exc, { "requested-uri": request.url, "error": error, "error_description": description }), status_code, {"Content-Type": "application/json"})) return make_response(( render_template( f"http-error-{str(status_code)[0:-2]}xx.html", error=exc, page=request.url, description=description, trace=traceback.format_exception(exc)), status_code, {"Content-Type": "text/html"})) return __handler__