Git based wiki inspired by Gollum
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

74 lines
2.0KB

  1. from __future__ import absolute_import
  2. from functools import wraps
  3. from flask_sqlalchemy import DeclarativeMeta
  4. def hook_func(name, fn):
  5. @wraps(fn)
  6. def wrapper(self, *args, **kwargs):
  7. for hook, a, kw in self.__class__._pre_hooks.get(name) or []:
  8. hook(self, *args, **kwargs)
  9. rv = fn(self, *args, **kwargs)
  10. # Attach return value for post hooks
  11. kwargs.update(dict(rv=rv))
  12. for hook, a, kw in self.__class__._post_hooks.get(name) or []:
  13. hook(self, *args, **kwargs)
  14. return rv
  15. return wrapper
  16. class HookMixinMeta(type):
  17. def __new__(cls, name, bases, attrs):
  18. super_new = super(HookMixinMeta, cls).__new__
  19. hookable = []
  20. for key, value in attrs.items():
  21. # Disallow hooking methods which start with an underscore (allow __init__ etc. still)
  22. if key.startswith('_') and not key.startswith('__'):
  23. continue
  24. if callable(value):
  25. attrs[key] = hook_func(key, value)
  26. hookable.append(key)
  27. attrs['_hookable'] = hookable
  28. return super_new(cls, name, bases, attrs)
  29. class HookMixin(object):
  30. __metaclass__ = HookMixinMeta
  31. _pre_hooks = {}
  32. _post_hooks = {}
  33. _hookable = []
  34. @classmethod
  35. def after(cls, method_name):
  36. assert method_name in cls._hookable, "'%s' not a hookable method of '%s'" % (method_name, cls.__name__)
  37. def outer(f, *args, **kwargs):
  38. cls._post_hooks.setdefault(method_name, []).append((f, args, kwargs))
  39. return f
  40. return outer
  41. @classmethod
  42. def before(cls, method_name):
  43. assert method_name in cls._hookable, "'%s' not a hookable method of '%s'" % (method_name, cls.__name__)
  44. def outer(f, *args, **kwargs):
  45. cls._pre_hooks.setdefault(method_name, []).append((f, args, kwargs))
  46. return f
  47. return outer
  48. class HookModelMeta(DeclarativeMeta, HookMixinMeta):
  49. pass