]> git.openstreetmap.org Git - osqa.git/blobdiff - forum/modules/decorators.py
Configure logging "the Django way" and ensure that all messages are written to the...
[osqa.git] / forum / modules / decorators.py
index 17d248b1559b378f950da64f53e87404afe2f1a8..05af3a6014119b72e8741ed8c07515a760ecedcc 100644 (file)
-import inspect\r
-\r
-class DecoratableObject(object):\r
-    def __init__(self, fn):\r
-        self._callable = fn\r
-\r
-    def decorate(self, fn, needs_origin):\r
-        origin = self._callable\r
-\r
-        if needs_origin:\r
-            self._callable = lambda *args, **kwargs: fn(origin, *args, **kwargs)\r
-        else:\r
-            self._callable = lambda *args, **kwargs: fn(*args, **kwargs)\r
-\r
-    def __call__(self, *args, **kwargs):\r
-        return self._callable(*args, **kwargs)\r
-\r
-\r
-def decoratable(fn):\r
-    return DecoratableObject(fn)\r
-\r
-def decoratable_method(fn):\r
-    obj = DecoratableObject(fn)\r
-    def decorated(self, *args, **kwargs):\r
-        return obj(self, *args, **kwargs)\r
-\r
-    decorated.__obj = obj\r
-    return decorated\r
-\r
-decoratable.method = decoratable_method\r
-\r
-def decorate(origin, needs_origin=True):\r
-    if not isinstance(origin, DecoratableObject):\r
-        if hasattr(origin, '__obj'):\r
-            def decorator(fn):\r
-                origin.__obj.decorate(fn, needs_origin)\r
-                return origin\r
-            return decorator\r
-\r
-        raise Exception('Not an decoratable function: %s' % origin.name)\r
-\r
-    def decorator(fn):\r
-        origin.decorate(fn, needs_origin)\r
-        return origin\r
-\r
-    return decorator\r
-\r
-\r
-\r
-\r
-\r
-\r
-\r
+import inspect
+
+class DecoratableObject(object):
+    MODE_OVERRIDE = 0
+    MODE_PARAMS = 1
+    MODE_RESULT = 2
+
+    def __init__(self, fn, is_method=False):
+        self._callable = fn
+        self.is_method = is_method
+
+        self._params_decoration = None
+        self._result_decoration = None
+
+    def _decorate(self, fn, mode, **kwargs):
+        if mode == self.MODE_OVERRIDE:
+            self._decorate_full(fn, **kwargs)
+        elif mode == self.MODE_PARAMS:
+            self._decorate_params(fn)
+        elif mode == self.MODE_RESULT:
+            self._decorate_result(fn, **kwargs)
+
+    def _decorate_full(self, fn, needs_origin=True):
+        origin = self._callable
+
+        if needs_origin:
+            if self.is_method:
+                self._callable = lambda inst, *args, **kwargs: fn(inst, origin, *args, **kwargs)
+            else:
+                self._callable = lambda *args, **kwargs: fn(origin, *args, **kwargs)
+        else:
+            self._callable = fn
+
+    def _decorate_params(self, fn):
+        if not self._params_decoration:
+            self._params_decoration = []
+
+        self._params_decoration.append(fn)
+
+    def _decorate_result(self, fn, needs_params=False):
+        if not self._result_decoration:
+            self._result_decoration = []
+
+        fn._needs_params = needs_params
+        self._result_decoration.append(fn)
+
+    def __call__(self, *args, **kwargs):
+        if self._params_decoration:
+            for dec in self._params_decoration:
+                try:
+                    args, kwargs = dec(*args, **kwargs)
+                except ReturnImediatelyException, e:
+                    return e.ret
+
+        res = self._callable(*args, **kwargs)
+
+        if self._result_decoration:
+            for dec in self._result_decoration:
+                if dec._needs_params:
+                    res = dec(res, *args, **kwargs)
+                else:
+                    res = dec(res)
+
+        return res
+
+class ReturnImediatelyException(Exception):
+    def __init__(self, ret):
+        super(Exception, self).__init__()
+        self.ret = ret
+
+def _check_decoratable(origin, install=True):
+    if not hasattr(origin, '_decoratable_obj'):
+        if inspect.ismethod(origin) and not hasattr(origin, '_decoratable_obj'):
+            decoratable = DecoratableObject(origin)
+
+            def decoratable_method(self, *args, **kwargs):
+                return decoratable(self, *args, **kwargs)
+
+            decoratable_method._decoratable_obj = decoratable
+
+            def decoratable_decorate(fn, mode, **kwargs):
+                decoratable._decorate(fn, mode, **kwargs)
+
+            decoratable_method._decorate = decoratable_decorate
+
+            if install:
+                setattr(origin.im_class, origin.__name__, decoratable_method)
+
+            return decoratable_method
+                
+        elif inspect.isfunction(origin):
+            decoratable = DecoratableObject(origin)
+
+            def decorated(*args, **kwargs):
+                return decoratable(*args, **kwargs)
+
+            decorated._decoratable_obj = decoratable
+
+            if install:
+                setattr(inspect.getmodule(origin), origin.__name__, decorated)
+
+            decorated.__name__ = origin.__name__
+            decorated.__module__ = origin.__module__
+
+            return decorated
+
+    return origin
+
+
+def decorate(origin, needs_origin=True):
+    origin = _check_decoratable(origin)
+
+    def decorator(fn):
+        origin._decoratable_obj._decorate(fn, DecoratableObject.MODE_OVERRIDE, needs_origin=needs_origin)
+        
+    return decorator
+
+
+def _decorate_params(origin):
+    origin = _check_decoratable(origin)
+
+    def decorator(fn):
+        origin._decoratable_obj._decorate(fn, DecoratableObject.MODE_PARAMS)
+
+    return decorator
+
+decorate.params = _decorate_params
+
+def _decorate_result(origin, needs_params=False):
+    origin = _check_decoratable(origin)
+
+    def decorator(fn):
+        origin._decoratable_obj._decorate(fn, DecoratableObject.MODE_RESULT, needs_params=needs_params)
+
+    return decorator
+
+decorate.result = _decorate_result
+
+def _decorate_with(fn):
+    def decorator(origin):
+        origin = _check_decoratable(origin)
+        origin._decoratable_obj._decorate(fn, DecoratableObject.MODE_OVERRIDE, needs_origin=True)
+        return origin
+    return decorator
+
+decorate.withfn = _decorate_with
+
+def _decorate_result_with(fn, needs_params=False):
+    def decorator(origin):
+        origin = _check_decoratable(origin)
+        origin._decoratable_obj._decorate(fn, DecoratableObject.MODE_RESULT, needs_params=needs_params)
+        return origin
+    return decorator
+
+decorate.result.withfn = _decorate_result_with
+
+def _decorate_params_with(fn):
+    def decorator(origin):
+        origin = _check_decoratable(origin)
+        origin._decoratable_obj._decorate(fn, DecoratableObject.MODE_PARAMS)
+        return origin
+    return decorator
+
+decorate.params.withfn = _decorate_params_with
\ No newline at end of file