about summary refs log tree commit diff
path: root/uploader/monadic_requests.py
diff options
context:
space:
mode:
authorFrederick Muriuki Muriithi2024-07-29 16:04:13 -0500
committerFrederick Muriuki Muriithi2024-08-05 09:52:18 -0500
commite16d7750c9f1e754a3e14a496380de0b014fffe1 (patch)
treec24e12b1381cd61363febfc5bcde165bd8fd0a46 /uploader/monadic_requests.py
parentd3fd64fb5237febb9628c4ccbd259969327ab2ec (diff)
downloadgn-uploader-e16d7750c9f1e754a3e14a496380de0b014fffe1.tar.gz
Provide a generalised way to handle errors and exceptions.
Diffstat (limited to 'uploader/monadic_requests.py')
-rw-r--r--uploader/monadic_requests.py48
1 files changed, 48 insertions, 0 deletions
diff --git a/uploader/monadic_requests.py b/uploader/monadic_requests.py
index f0a60f4..aa34951 100644
--- a/uploader/monadic_requests.py
+++ b/uploader/monadic_requests.py
@@ -1,9 +1,57 @@
 """Wrap requests functions with monads."""
+import traceback
+from typing import Union, Optional, Callable
+
 import requests
+from requests.models import Response
 from pymonad.either import Left, Right, Either
+from flask import (
+    flash,
+    request,
+    redirect,
+    render_template,
+    current_app as app,
+    escape as flask_escape)
 
+# HTML Status codes indicating a successful request.
 SUCCESS_CODES = (200, 201, 202, 203, 204, 205, 206, 207, 208, 226)
 
+# Possible error(s) that can be encontered while attempting to do a request.
+PossibleError = Union[Response, Exception]
+
+
+def make_error_handler(
+        redirect_to: Optional[Response] = None,
+        cleanup_thunk: Callable = lambda *args: None
+) -> Callable[[PossibleError], Response]:
+    """
+    Build a function to gracefully handle errors encountered while doing
+    requests.
+
+    :rtype: Callable
+    """
+    redirect_to = redirect_to or redirect(request.url)
+    def __handler__(resp_or_exc: PossibleError) -> Response:
+        cleanup_thunk()
+        if issubclass(type(resp_or_exc), Exception):
+            # Is an exception!
+            return render_template(
+                "unhandled_exception.html",
+                trace=traceback.format_exception(resp_or_exc))
+        if isinstance(resp_or_exc, Response):
+            flash("The authorisation server responded with "
+                  f"({flask_escape(resp_or_exc.status_code)}, "
+                  f"{flask_escape(resp_or_exc.reason)}) for the request to "
+                  f"'{flask_escape(resp_or_exc.request.url)}'",
+                  "alert-danger")
+            return redirect_to
+
+        flash("Unspecified error!", "alert-danger")
+        app.logger.debug("Error (%s): %s", type(resp_or_exc), resp_or_exc)
+        return redirect_to
+    return __handler__
+
+
 def get(url, params=None, **kwargs) -> Either:
     """
     A wrapper around `requests.get` function.