import inspect\r
\r
class DecoratableObject(object):\r
- def __init__(self, fn):\r
+ MODE_OVERRIDE = 0\r
+ MODE_PARAMS = 1\r
+ MODE_RESULT = 2\r
+\r
+ def __init__(self, fn, is_method=False):\r
self._callable = fn\r
+ self.is_method = is_method\r
+\r
+ self._params_decoration = None\r
+ self._result_decoration = None\r
+\r
+ def _decorate(self, fn, mode, **kwargs):\r
+ if mode == self.MODE_OVERRIDE:\r
+ self._decorate_full(fn, **kwargs)\r
+ elif mode == self.MODE_PARAMS:\r
+ self._decorate_params(fn)\r
+ elif mode == self.MODE_RESULT:\r
+ self._decorate_result(fn, **kwargs)\r
\r
- def decorate(self, fn, needs_origin):\r
+ def _decorate_full(self, fn, needs_origin=True):\r
origin = self._callable\r
\r
if needs_origin:\r
- self._callable = lambda *args, **kwargs: fn(origin, *args, **kwargs)\r
+ if self.is_method:\r
+ self._callable = lambda inst, *args, **kwargs: fn(inst, origin, *args, **kwargs)\r
+ else:\r
+ self._callable = lambda *args, **kwargs: fn(origin, *args, **kwargs)\r
else:\r
- self._callable = lambda *args, **kwargs: fn(*args, **kwargs)\r
+ self._callable = fn\r
+\r
+ def _decorate_params(self, fn):\r
+ if not self._params_decoration:\r
+ self._params_decoration = []\r
+\r
+ self._params_decoration.append(fn)\r
+\r
+ def _decorate_result(self, fn, needs_params=False):\r
+ if not self._result_decoration:\r
+ self._result_decoration = []\r
+\r
+ fn._needs_params = needs_params\r
+ self._result_decoration.append(fn)\r
\r
def __call__(self, *args, **kwargs):\r
- return self._callable(*args, **kwargs)\r
+ if self._params_decoration:\r
+ for dec in self._params_decoration:\r
+ args, kwargs = dec(*args, **kwargs)\r
+\r
+ res = self._callable(*args, **kwargs)\r
+\r
+ if self._result_decoration:\r
+ for dec in self._result_decoration:\r
+ if dec._needs_params:\r
+ res = dec(res, *args, **kwargs)\r
+ else:\r
+ res = dec(res)\r
+\r
+ return res\r
+\r
+def _check_decoratable(origin, install=True):\r
+ if not isinstance(origin, DecoratableObject):\r
+ if inspect.ismethod(origin) and not hasattr(origin, '_decoratable_obj'):\r
+ decoratable = DecoratableObject(origin)\r
+\r
+ def decoratable_method(self, *args, **kwargs):\r
+ return decoratable(self, *args, **kwargs)\r
+\r
+ decoratable_method._decoratable_obj = decoratable\r
+\r
+ def decoratable_decorate(fn, mode, **kwargs):\r
+ decoratable._decorate(fn, mode, **kwargs)\r
+\r
+ decoratable_method._decorate = decoratable_decorate\r
+\r
+ if install:\r
+ setattr(origin.im_class, origin.__name__, decoratable_method)\r
\r
+ return decoratable_method\r
+ \r
+ elif inspect.isfunction(origin):\r
+ decoratable = DecoratableObject(origin)\r
\r
-def decoratable(fn):\r
- return DecoratableObject(fn)\r
+ if install:\r
+ setattr(inspect.getmodule(origin), origin.__name__, decoratable)\r
\r
-def decoratable_method(fn):\r
- obj = DecoratableObject(fn)\r
- def decorated(self, *args, **kwargs):\r
- return obj(self, *args, **kwargs)\r
+ return decoratable\r
\r
- decorated.__obj = obj\r
- return decorated\r
+ return origin\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
+ origin = _check_decoratable(origin)\r
+\r
+ def decorator(fn):\r
+ origin._decorate(fn, DecoratableObject.MODE_OVERRIDE, needs_origin=needs_origin)\r
+ \r
+ return decorator\r
\r
- raise TypeError('Not a decoratable function: %s' % origin.__name__)\r
+\r
+def _decorate_params(origin):\r
+ origin = _check_decoratable(origin)\r
\r
def decorator(fn):\r
- origin.decorate(fn, needs_origin)\r
- return origin\r
+ origin._decorate(fn, DecoratableObject.MODE_PARAMS)\r
\r
return decorator\r
\r
+decorate.params = _decorate_params\r
+\r
+def _decorate_result(origin, needs_params=False):\r
+ origin = _check_decoratable(origin)\r
+\r
+ def decorator(fn):\r
+ origin._decorate(fn, DecoratableObject.MODE_RESULT, needs_params=needs_params)\r
\r
-def decorate_all(module):\r
- [setattr(module, n, decoratable(f)) for n, f in\r
- [(n, getattr(module, n)) for n in dir(module)]\r
- if (callable(f)) and (not inspect.isclass(f)) and (f.__module__ == module.__name__)]\r
+ return decorator\r
\r
+decorate.result = _decorate_result\r
\r
+def _decorate_with(fn):\r
+ def decorator(origin):\r
+ origin = _check_decoratable(origin)\r
+ origin._decorate(fn, DecoratableObject.MODE_OVERRIDE, needs_origin=True)\r
+ return origin\r
+ return decorator\r
\r
+decorate.withfn = _decorate_with\r
\r
+def _decorate_result_with(fn, needs_params=False):\r
+ def decorator(origin):\r
+ origin = _check_decoratable(origin)\r
+ origin._decorate(fn, DecoratableObject.MODE_RESULT, needs_params=needs_params)\r
+ return origin\r
+ return decorator\r
\r
+decorate.result.withfn = _decorate_result_with\r
\r
+def _decorate_params_with(fn):\r
+ def decorator(origin):\r
+ origin = _check_decoratable(origin)\r
+ origin._decorate(fn, DecoratableObject.MODE_PARAMS)\r
+ return origin\r
+ return decorator\r
\r
+decorate.params.withfn = _decorate_params_with
\ No newline at end of file