No Description
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.

hooks.py 4.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115
  1. #
  2. # This file is part of Lodel 2 (https://github.com/OpenEdition)
  3. #
  4. # Copyright (C) 2015-2017 Cléo UMS-3287
  5. #
  6. # This program is free software: you can redistribute it and/or modify
  7. # it under the terms of the GNU Affero General Public License as published
  8. # by the Free Software Foundation, either version 3 of the License, or
  9. # (at your option) any later version.
  10. #
  11. # This program is distributed in the hope that it will be useful,
  12. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. # GNU Affero General Public License for more details.
  15. #
  16. # You should have received a copy of the GNU Affero General Public License
  17. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. #
  19. ## @package lodel.plugin.hooks This module deals with the Hook management in Lodel
  20. import os
  21. import copy
  22. from lodel.context import LodelContext
  23. ## @brief Class designed to handle a hook's callback with a priority
  24. class DecoratedWrapper(object):
  25. ##
  26. # @param hook function : the function to wrap
  27. # @param priority int : the callbacl priority
  28. def __init__(self, hook, priority):
  29. self._priority = priority
  30. self._hook = hook
  31. ## @brief Calls the callback
  32. # @param hook_name str : The name of the called hook
  33. # @param caller * : The caller (depends on the hook)
  34. # @param payload * : Datas that depends on the hook
  35. # @return modified payload
  36. def __call__(self, hook_name, caller, payload):
  37. return self._hook(hook_name, caller, payload)
  38. ## @brief Returns the string representation of the class
  39. # It shows the name and the priority of the hook
  40. def __str__(self):
  41. return "<LodelHook '%s' priority = %s>" % (
  42. self._hook.__name__, self._priority)
  43. ## @brief Decorator designed to register hook's callbacks
  44. # @ingroup lodel2_plugins
  45. #
  46. # @note Decorated functions are expected to take 3 arguments :
  47. #  - hook_name : the called hook name
  48. # - caller : the hook caller (depends on the hook)
  49. # - payload : datas depending on the hook
  50. class LodelHook(object):
  51. ## @brief Stores all hooks (DecoratedWrapper instances)
  52. _hooks = dict()
  53. ##
  54. # @param hook_name str : the name of the hook to register to
  55. # @param priority int : the hook priority (default value : None)
  56. def __init__(self, hook_name, priority = None):
  57. self._hook_name = hook_name
  58. self._priority = 0xFFFF if priority is None else priority
  59. ## @brief called just after __init__
  60. # @param hook function : the decorated function
  61. # @return the hook argument
  62. def __call__(self, hook):
  63. if not self._hook_name in self._hooks:
  64. self._hooks[self._hook_name] = list()
  65. wrapped = DecoratedWrapper(hook, self._priority)
  66. self._hooks[self._hook_name].append(wrapped)
  67. self._hooks[self._hook_name] = sorted(self._hooks[self._hook_name], key = lambda h: h._priority)
  68. return hook
  69. ## @brief Calls a hook
  70. # @param hook_name str : the hook's name
  71. # @param caller * : the hook caller (depends on the hook)
  72. # @param payload * : datas for the hook
  73. # @return modified payload
  74. @classmethod
  75. def call_hook(cls, hook_name, caller, payload):
  76. LodelContext.expose_modules(globals(), {'lodel.logger': 'logger'})
  77. logger.debug("Calling hook '%s'" % hook_name)
  78. if hook_name in cls._hooks:
  79. for hook in cls._hooks[hook_name]:
  80. logger.debug("Lodel hook '%s' calls %s" % (
  81. hook_name, hook))
  82. payload = hook(hook_name, caller, payload)
  83. return payload
  84. ## @brief Fetches registered hooks
  85. # @param names list | None : optionnal filter on name (default value : None)
  86. # @return dict containing for each name a list of the hooks and their priorities
  87. @classmethod
  88. def hook_list(cls, names = None):
  89. res = None
  90. if names is not None:
  91. res = { name: copy.copy(cls._hooks[name]) for name in cls._hooks if name in names}
  92. else:
  93. res = copy.copy(cls._hooks)
  94. return { name: [(hook._hook, hook._priority) for hook in hooks] for name, hooks in res.items() }
  95. ## @brief Unregister all hooks
  96. # @warning REALLY NOT a good idea !
  97. # @note implemented for testing purpose
  98. @classmethod
  99. def __reset__(cls):
  100. cls._hooks = dict()