mirror of
https://github.com/yweber/lodel2.git
synced 2025-10-26 02:39:01 +02:00
Add the possibility to add custom methods ton LeAPI dynamic objects using plugin
This commit is contained in:
parent
6a6396f0d2
commit
36bded3051
5 changed files with 134 additions and 3 deletions
|
|
@ -47,6 +47,8 @@ def datasource_init_hook():
|
||||||
def lodel2_dyncode_datasources_init(self, caller, payload):
|
def lodel2_dyncode_datasources_init(self, caller, payload):
|
||||||
for cls in dynclasses:
|
for cls in dynclasses:
|
||||||
cls._init_datasources()
|
cls._init_datasources()
|
||||||
|
from lodel.plugin.hooks import LodelHook
|
||||||
|
LodelHook.call_hook("lodel2_dyncode_loaded", __name__, dynclasses)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
##@brief return A list of EmClass sorted by dependencies
|
##@brief return A list of EmClass sorted by dependencies
|
||||||
|
|
|
||||||
|
|
@ -40,4 +40,4 @@
|
||||||
#
|
#
|
||||||
|
|
||||||
from .hooks import LodelHook
|
from .hooks import LodelHook
|
||||||
from .plugins import Plugin
|
from .plugins import Plugin, CustomMethod
|
||||||
|
|
|
||||||
|
|
@ -33,3 +33,8 @@ def datasources_bootstrap_callaback(hook_name, caller, payload):
|
||||||
log_msg = "Found a datasource named '%s' identified by '%s'"
|
log_msg = "Found a datasource named '%s' identified by '%s'"
|
||||||
log_msg %= (ds_name, identifier)
|
log_msg %= (ds_name, identifier)
|
||||||
logger.debug(log_msg)
|
logger.debug(log_msg)
|
||||||
|
|
||||||
|
@LodelHook("lodel2_dyncode_loaded")
|
||||||
|
def lodel2_plugins_custom_methods(self, caller, dynclasses):
|
||||||
|
from lodel.plugin.plugins import CustomMethod
|
||||||
|
CustomMethod.set_registered(dynclasses)
|
||||||
|
|
|
||||||
|
|
@ -348,6 +348,118 @@ class Plugin(object):
|
||||||
if cls._load_called != []:
|
if cls._load_called != []:
|
||||||
cls._load_called = []
|
cls._load_called = []
|
||||||
|
|
||||||
|
##@brief Decorator class designed to allow plugins to add custom methods
|
||||||
|
#to LeObject childs (dyncode objects)
|
||||||
|
#
|
||||||
|
class CustomMethod(object):
|
||||||
|
##@brief Stores registered custom methods
|
||||||
|
#
|
||||||
|
#Key = LeObject child class name
|
||||||
|
#Value = CustomMethod instance
|
||||||
|
_custom_methods = dict()
|
||||||
|
|
||||||
|
INSTANCE_METHOD = 0
|
||||||
|
CLASS_METHOD = 1
|
||||||
|
STATIC_METHOD = 2
|
||||||
|
|
||||||
|
##@brief Decorator constructor
|
||||||
|
#@param component_name str : the name of the component to enhance
|
||||||
|
#@param method_name str : the name of the method to inject (if None given
|
||||||
|
#@param method_type int : take value in one of
|
||||||
|
#CustomMethod::INSTANCE_METHOD CustomMethod::CLASS_METHOD or
|
||||||
|
#CustomMethod::STATIC_METHOD
|
||||||
|
#use the function name
|
||||||
|
def __init__(self, component_name, method_name = None, method_type=0):
|
||||||
|
##@brief The targeted LeObject child class
|
||||||
|
self._comp_name = component_name
|
||||||
|
##@brief The method name
|
||||||
|
self._method_name = method_name
|
||||||
|
##@brief The function (that will be the injected method)
|
||||||
|
self._fun = None
|
||||||
|
##@brief Stores the type of method (instance, class or static)
|
||||||
|
self._type = int(method_type)
|
||||||
|
if self._type not in (self.INSTANCE_METHOD, self.CLASS_METHOD,\
|
||||||
|
self.STATIC_METHOD):
|
||||||
|
raise ValueError("Excepted value for method_type was one of \
|
||||||
|
CustomMethod::INSTANCE_METHOD CustomMethod::CLASS_METHOD or \
|
||||||
|
CustomMethod::STATIC_METHOD, but got %s" % self._type)
|
||||||
|
|
||||||
|
##@brief called just after __init__
|
||||||
|
#@param fun function : the decorated function
|
||||||
|
#@param return the function
|
||||||
|
def __call__(self, fun):
|
||||||
|
if self._method_name is None:
|
||||||
|
self._method_name = fun.__name__
|
||||||
|
if self._comp_name not in self._custom_methods:
|
||||||
|
self._custom_methods[self._comp_name] = list()
|
||||||
|
|
||||||
|
if self._method_name in [ scm._method_name for scm in self._custom_methods[self._comp_name]]:
|
||||||
|
raise RuntimeError("A method named %s allready registered by \
|
||||||
|
another plugin : %s" % (
|
||||||
|
self._method_name,
|
||||||
|
self._custom_methods[self._comp_name].__module__))
|
||||||
|
self._fun = fun
|
||||||
|
self._custom_methods[self._comp_name].append(self)
|
||||||
|
|
||||||
|
##@brief Textual representation
|
||||||
|
#@return textual representation of the CustomMethod instance
|
||||||
|
def __repr__(self):
|
||||||
|
res = "<CustomMethod name={method_name} target={classname} \
|
||||||
|
source={module_name}.{fun_name}>"
|
||||||
|
return res.format(
|
||||||
|
method_name = self._method_name,
|
||||||
|
classname = self._comp_name,
|
||||||
|
module_name = self._fun.__module__,
|
||||||
|
fun_name = self._fun.__name__)
|
||||||
|
|
||||||
|
##@brief Return a well formed method
|
||||||
|
#
|
||||||
|
#@note the type of method depends on the _type attribute
|
||||||
|
#@return a method directly injectable in the target class
|
||||||
|
def __get_method(self):
|
||||||
|
if self._type == self.INSTANCE_METHOD:
|
||||||
|
def custom__get__(self, obj, objtype = None):
|
||||||
|
return types.MethodType(self, obj, objtype)
|
||||||
|
setattr(self._fun, '__get__', custom__get__)
|
||||||
|
return self._fun
|
||||||
|
elif self._type == self.CLASS_METHOD:
|
||||||
|
return classmethod(self._fun)
|
||||||
|
elif self._type == self.STATIC_METHOD:
|
||||||
|
return staticmethod(self._fun)
|
||||||
|
else:
|
||||||
|
raise RuntimeError("Attribute _type is not one of \
|
||||||
|
CustomMethod::INSTANCE_METHOD CustomMethod::CLASS_METHOD \
|
||||||
|
CustomMethod::STATIC_METHOD")
|
||||||
|
|
||||||
|
##@brief Handle custom method dynamic injection in LeAPI dyncode
|
||||||
|
#
|
||||||
|
#Called by lodel2_dyncode_loaded hook defined at
|
||||||
|
#lodel.plugin.core_hooks.lodel2_plugin_custom_methods()
|
||||||
|
#
|
||||||
|
#@param cls
|
||||||
|
#@param dynclasses LeObject child classes : List of dynamically generated
|
||||||
|
#LeObject child classes
|
||||||
|
@classmethod
|
||||||
|
def set_registered(cls, dynclasses):
|
||||||
|
from lodel import logger
|
||||||
|
dyn_cls_dict = { dc.__name__:dc for dc in dynclasses}
|
||||||
|
for cls_name, custom_methods in cls._custom_methods.items():
|
||||||
|
for custom_method in custom_methods:
|
||||||
|
if cls_name not in dyn_cls_dict:
|
||||||
|
logger.error("Custom method %s adding fails : No dynamic \
|
||||||
|
LeAPI objects named %s." % (custom_method, cls_name))
|
||||||
|
elif custom_method._method_name in dir(dyn_cls_dict[cls_name]):
|
||||||
|
logger.warning("Overriding existing method '%s' on target \
|
||||||
|
with %s" % (custom_method._method_name, custom_method))
|
||||||
|
else:
|
||||||
|
setattr(
|
||||||
|
dyn_cls_dict[cls_name],
|
||||||
|
custom_method._method_name,
|
||||||
|
custom_method.__get_method())
|
||||||
|
logger.debug(
|
||||||
|
"Custom method %s added to target" % custom_method)
|
||||||
|
|
||||||
|
|
||||||
##@page lodel2_plugins Lodel2 plugins system
|
##@page lodel2_plugins Lodel2 plugins system
|
||||||
#
|
#
|
||||||
# @par Plugin structure
|
# @par Plugin structure
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
#-*- coding: utf-8 -*-
|
#-*- coding: utf-8 -*-
|
||||||
|
|
||||||
from lodel.plugin import LodelHook
|
from lodel.plugin import LodelHook, CustomMethod
|
||||||
|
|
||||||
@LodelHook('leapi_get_post')
|
@LodelHook('leapi_get_post')
|
||||||
@LodelHook('leapi_update_pre')
|
@LodelHook('leapi_update_pre')
|
||||||
|
|
@ -12,4 +12,16 @@ from lodel.plugin import LodelHook
|
||||||
def dummy_callback(hook_name, caller, payload):
|
def dummy_callback(hook_name, caller, payload):
|
||||||
if Lodel.settings.Settings.debug:
|
if Lodel.settings.Settings.debug:
|
||||||
print("\tHook %s\tcaller %s with %s" % (hook_name, caller, payload))
|
print("\tHook %s\tcaller %s with %s" % (hook_name, caller, payload))
|
||||||
return payload
|
return payload
|
||||||
|
|
||||||
|
|
||||||
|
@CustomMethod('Object', 'dummy_method')
|
||||||
|
def dummy_instance_method(self):
|
||||||
|
print("Hello world !\
|
||||||
|
I'm a custom method on an instance of class %s" % self.__class__)
|
||||||
|
|
||||||
|
|
||||||
|
@CustomMethod('Object', 'dummy_class_method', CustomMethod.CLASS_METHOD)
|
||||||
|
def dummy_instance_method(self):
|
||||||
|
print("Hello world !\
|
||||||
|
I'm a custom method on class %s" % self.__class__)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue