Sin descripción
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 3.3KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. #-*- coding: utf-8 -*-
  2. import os
  3. import copy
  4. from importlib.machinery import SourceFileLoader
  5. ##@brief Class designed to handle a hook's callback with a priority
  6. class DecoratedWrapper(object):
  7. ##@brief Constructor
  8. # @param hook function : the function to wrap
  9. # @param priority int : the callbacl priority
  10. def __init__(self, hook, priority):
  11. self._priority = priority
  12. self._hook = hook
  13. ##@brief Call the callback
  14. # @param hook_name str : The name of the called hook
  15. # @param caller * : The caller (depends on the hook)
  16. # @param payload * : Datas that depends on the hook
  17. # @return modified payload
  18. def __call__(self, hook_name, caller, payload):
  19. return self._hook(hook_name, caller, payload)
  20. def __str__(self):
  21. return "<LodelHook '%s' priority = %s>" % (
  22. self._hook.__name__, self._priority)
  23. ##@brief Decorator designed to register hook's callbacks
  24. #
  25. # @note Decorated functions are expected to take 3 arguments :
  26. #  - hook_name : the called hook name
  27. # - caller : the hook caller (depends on the hook)
  28. # - payload : datas depending on the hook
  29. class LodelHook(object):
  30. ##@brief Stores all hooks (DecoratedWrapper instances)
  31. _hooks = dict()
  32. ##@brief Decorator constructor
  33. # @param hook_name str : the name of the hook to register to
  34. # @param priority int : the hook priority
  35. def __init__(self, hook_name, priority = None):
  36. self._hook_name = hook_name
  37. self._priority = 0xFFFF if priority is None else priority
  38. ##@brief called just after __init__
  39. # @param hook function : the decorated function
  40. # @return the hook argument
  41. def __call__(self, hook):
  42. if not self._hook_name in self._hooks:
  43. self._hooks[self._hook_name] = list()
  44. wrapped = DecoratedWrapper(hook, self._priority)
  45. self._hooks[self._hook_name].append(wrapped)
  46. self._hooks[self._hook_name] = sorted(self._hooks[self._hook_name], key = lambda h: h._priority)
  47. return hook
  48. ##@brief Call hooks
  49. # @param hook_name str : the hook's name
  50. # @param caller * : the hook caller (depends on the hook)
  51. # @param payload * : datas for the hook
  52. # @param cls
  53. # @return modified payload
  54. @classmethod
  55. def call_hook(cls, hook_name, caller, payload):
  56. from lodel import logger
  57. logger.info("Calling hook '%s'" % hook_name)
  58. if hook_name in cls._hooks:
  59. for hook in cls._hooks[hook_name]:
  60. logger.info("Lodel hook '%s' calls %s" % (
  61. hook_name, hook))
  62. payload = hook(hook_name, caller, payload)
  63. return payload
  64. ##@brief Fetch registered hooks
  65. # @param names list | None : optionnal filter on name
  66. # @param cls
  67. # @return a list of functions
  68. @classmethod
  69. def hook_list(cls, names = None):
  70. res = None
  71. if names is not None:
  72. res = { name: copy.copy(cls._hooks[name]) for name in cls._hooks if name in names}
  73. else:
  74. res = copy.copy(cls._hooks)
  75. return { name: [(hook._hook, hook._priority) for hook in hooks] for name, hooks in res.items() }
  76. ##@brief Unregister all hooks
  77. # @param cls
  78. # @warning REALLY NOT a good idea !
  79. # @note implemented for testing purpose
  80. @classmethod
  81. def __reset__(cls):
  82. cls._hooks = dict()