hook.py 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119
  1. """Cement core hooks module."""
  2. import operator
  3. from ..core import backend, exc
  4. from ..utils.misc import minimal_logger
  5. LOG = minimal_logger(__name__)
  6. def define(name):
  7. """
  8. Define a hook namespace that plugins can register hooks in.
  9. :param name: The name of the hook, stored as hooks['name']
  10. :raises: cement.core.exc.FrameworkError
  11. Usage:
  12. .. code-block:: python
  13. from cement.core import hook
  14. hook.define('myhookname_hook')
  15. """
  16. LOG.debug("defining hook '%s'" % name)
  17. if name in backend.__hooks__:
  18. raise exc.FrameworkError("Hook name '%s' already defined!" % name)
  19. backend.__hooks__[name] = []
  20. def defined(hook_name):
  21. """
  22. Test whether a hook name is defined.
  23. :param hook_name: The name of the hook.
  24. I.e. ``my_hook_does_awesome_things``.
  25. :returns: True if the hook is defined, False otherwise.
  26. :rtype: boolean
  27. """
  28. if hook_name in backend.__hooks__:
  29. return True
  30. else:
  31. return False
  32. def register(name, func, weight=0):
  33. """
  34. Register a function to a hook. The function will be called, in order of
  35. weight, when the hook is run.
  36. :param name: The name of the hook to register too. I.e. ``pre_setup``,
  37. ``post_run``, etc.
  38. :param func: The function to register to the hook. This is an
  39. *un-instantiated*, non-instance method, simple function.
  40. :param weight: The weight in which to order the hook function.
  41. :type weight: integer
  42. Usage:
  43. .. code-block:: python
  44. from cement.core import hook
  45. def my_hook(*args, **kwargs):
  46. # do something here
  47. res = 'Something to return'
  48. return res
  49. hook.register('post_setup', my_hook)
  50. """
  51. if name not in backend.__hooks__:
  52. LOG.debug("hook name '%s' is not defined! ignoring..." % name)
  53. return False
  54. LOG.debug("registering hook '%s' from %s into hooks['%s']" %
  55. (func.__name__, func.__module__, name))
  56. # Hooks are as follows: (weight, name, func)
  57. backend.__hooks__[name].append((int(weight), func.__name__, func))
  58. def run(name, *args, **kwargs):
  59. """
  60. Run all defined hooks in the namespace. Yields the result of each hook
  61. function run.
  62. :param name: The name of the hook function.
  63. :param args: Additional arguments to be passed to the hook functions.
  64. :param kwargs: Additional keyword arguments to be passed to the hook
  65. functions.
  66. :raises: FrameworkError
  67. Usage:
  68. .. code-block:: python
  69. from cement.core import hook
  70. for result in hook.run('hook_name'):
  71. # do something with result from each hook function
  72. ...
  73. """
  74. if name not in backend.__hooks__:
  75. raise exc.FrameworkError("Hook name '%s' is not defined!" % name)
  76. # Will order based on weight (the first item in the tuple)
  77. backend.__hooks__[name].sort(key=operator.itemgetter(0))
  78. for hook in backend.__hooks__[name]:
  79. LOG.debug("running hook '%s' (%s) from %s" %
  80. (name, hook[2], hook[2].__module__))
  81. res = hook[2](*args, **kwargs)
  82. # Results are yielded, so you must fun a for loop on it, you can not
  83. # simply call run_hooks().
  84. yield res