]> git-server-git.apps.pok.os.sepia.ceph.com Git - radosgw-agent.git/commitdiff
add a decorator utility module
authorAlfredo Deza <adeza@redhat.com>
Thu, 5 Mar 2015 19:59:24 +0000 (14:59 -0500)
committerAlfredo Deza <adeza@redhat.com>
Thu, 5 Mar 2015 19:59:24 +0000 (14:59 -0500)
Signed-off-by: Alfredo Deza <adeza@redhat.com>
radosgw_agent/util/__init__.py
radosgw_agent/util/decorators.py [new file with mode: 0644]

index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..977f6d03e07979b3dfd317f31c8db391bd72909f 100644 (file)
@@ -0,0 +1 @@
+import log
diff --git a/radosgw_agent/util/decorators.py b/radosgw_agent/util/decorators.py
new file mode 100644 (file)
index 0000000..1a063a4
--- /dev/null
@@ -0,0 +1,112 @@
+import logging
+import sys
+import traceback
+from functools import wraps
+
+
+def catches(catch=None, handler=None, exit=True, handle_all=False):
+    """
+    Very simple decorator that tries any of the exception(s) passed in as
+    a single exception class or tuple (containing multiple ones) returning the
+    exception message and optionally handling the problem if it raises with the
+    handler if it is provided.
+
+    So instead of doing something like this::
+
+        def bar():
+            try:
+                some_call()
+                print "Success!"
+            except TypeError, exc:
+                print "Error while handling some call: %s" % exc
+                sys.exit(1)
+
+    You would need to decorate it like this to have the same effect::
+
+        @catches(TypeError)
+        def bar():
+            some_call()
+            print "Success!"
+
+    If multiple exceptions need to be caught they need to be provided as a
+    tuple::
+
+        @catches((TypeError, AttributeError))
+        def bar():
+            some_call()
+            print "Success!"
+
+    If adding a handler, it should accept a single argument, which would be the
+    exception that was raised, it would look like::
+
+        def my_handler(exc):
+            print 'Handling exception %s' % str(exc)
+            raise SystemExit
+
+        @catches(KeyboardInterrupt, handler=my_handler)
+        def bar():
+            some_call()
+
+    Note that the handler needs to raise its SystemExit if it wants to halt
+    execution, otherwise the decorator would continue as a normal try/except
+    block.
+
+
+    :param catch: A tuple with one (or more) Exceptions to catch
+    :param handler: Optional handler to have custom handling of exceptions
+    :param exit: Raise a ``SystemExit`` after handling exceptions
+    :param handle_all: Handle all other exceptions via logging.
+    """
+    catch = catch or Exception
+    logger = logging.getLogger('radosgw_agent')
+
+    def decorate(f):
+
+        @wraps(f)
+        def newfunc(*a, **kw):
+            exit_from_catch = False
+            try:
+                return f(*a, **kw)
+            except catch as e:
+                if handler:
+                    return handler(e)
+                else:
+                    logger.error(make_exception_message(e))
+
+                    if exit:
+                        exit_from_catch = True
+                        sys.exit(1)
+            except Exception:  # anything else, no need to save the exception as a variable
+                if handle_all is False:  # re-raise if we are not supposed to handle everything
+                    raise
+                # Make sure we don't spit double tracebacks if we are raising
+                # SystemExit from the `except catch` block
+
+                if exit_from_catch:
+                    sys.exit(1)
+
+                str_failure = traceback.format_exc()
+                for line in str_failure.split('\n'):
+                    logger.error("%s" % line)
+                sys.exit(1)
+
+        return newfunc
+
+    return decorate
+
+#
+# Decorator helpers
+#
+
+
+def make_exception_message(exc):
+    """
+    An exception is passed in and this function
+    returns the proper string depending on the result
+    so it is readable enough.
+    """
+    if str(exc):
+        return '%s: %s\n' % (exc.__class__.__name__, exc)
+    else:
+        return '%s\n' % (exc.__class__.__name__)
+