__author__ = 'Kegan Holtzhausen <Kegan.Holtzhausen@unibet.com>'
"""
The plugin system
"""
import functools
import logging
from collections import OrderedDict
from libsolace.util import get_calling_module
[docs]class PluginClass(type):
"""This is a metaclass for construction only, see Plugin rather"""
def __new__(cls, clsname, bases, dct):
new_object = super(PluginClass, cls).__new__(cls, clsname, bases, dct)
return new_object
[docs]class Plugin(object):
"""This is the plugin core object where all plugins should extend from and register too.
Plugin Example:
.. doctest::
:options: +SKIP
>>> import pprint
>>> import libsolace
>>> from libsolace.plugin import Plugin
>>> @libsolace.plugin_registry.register
>>> class Bar(Plugin):
>>> plugin_name = "BarPlugin"
>>> def __init__(self):
>>> pass
>>> # Instance methods work!
>>> def hello(self, name):
>>> print("Hello %s from %s" % (name, self))
>>> # Static methods work too!
>>> @staticmethod
>>> def gbye():
>>> print("Cheers!")
>>> libsolace.plugin_registry('BarPlugin').hello("dude")
>>> libsolace.plugin_registry('BarPlugin').gbye()
>>> pprint.pprint(dir(libsolace.plugin_registry('BarPlugin')))
Plugin Instantiation:
>>> import libsolace.settingsloader as settings
>>> from libsolace.SolaceAPI import SolaceAPI
>>> api = SolaceAPI("dev")
>>> my_plugin = api.manage("NullPlugin")
>>> type(my_plugin)
<class 'libsolace.items.NullPlugin.NullPlugin'>
Direct Instantiation:
>>> import libsolace.settingsloader as settings
>>> import libsolace
>>> my_clazz = libsolace.plugin_registry("NullPlugin", settings=settings)
>>> my_instance = my_clazz(settings=settings)
"""
__metaclass__ = PluginClass
plugins = []
plugins_dict = OrderedDict()
plugin_name = "Plugin"
""" the plugin's name, override this in the derived class!"""
exists = False
def __init__(self, *args, **kwargs):
logging.debug("Plugin Init: %s, %s" % (args, kwargs))
[docs] def register(self, object_class, *args, **kwargs):
"""
Registers a object with the plugin registry, typically used as a decorator.
:param object_class: the class to register as a plugin
Example:
.. doctest::
:options: +SKIP
>>> @libsolace.plugin_registry.register
>>> class Foo(Plugin)
>>> ...
"""
logging.info("Registering Plugin id: %s from class: %s " % (object_class.plugin_name, object_class))
o = object_class
self.plugins.append(o)
self.plugins_dict[object_class.plugin_name] = o
def _d(fn):
logging.info("CALL CALL CALL CALL CALL CALL")
return functools.update_wrapper(object_class(fn), fn)
functools.update_wrapper(_d, object_class)
return _d
def __call__(self, *args, **kwargs):
"""
When you call the registry with the name of a plugin eg: 'NullPlugin', as the first arg, this returns the class
from the plugin_registry. You can then instantiate the class in any way you need to.
Example
>>> import libsolace
>>> from libsolace.plugin import Plugin
>>> a = libsolace.plugin_registry("NullPlugin")
>>> type(a)
""
:param args: name of Plugin to return
:param kwargs:
:return: class
"""
try:
module = get_calling_module(point=2)
except:
module = "Unknown"
try:
module_parent = get_calling_module(point=3)
except:
module_parent = "Unknown"
logging.debug(self.plugins_dict)
logging.info("Module %s->%s->%s" % (module_parent, module, args[0]))
logging.debug("Plugin Request: args: %s, kwargs: %s" % (args, kwargs))
try:
logging.debug("Class: %s" % self.plugins_dict[args[0]])
return self.plugins_dict[args[0]]
except:
logging.warn("No plugin named: %s found, available plugins are: %s" % (args[0], self.plugins_dict))
logging.warn(
"Please check the plugin is listed in the yaml config and that you have @libsolace.plugin_registry.register in the class")
raise
[docs] def set_exists(self, state):
"""set_exists is used as caching in order to cut down on SEMP queries to validate existence of items. For example,
if you create a new VPN in "batch" mode, After the "create-vpn" XML is generated, set_exists is set to True so
subsequent requests decorated with the `only_if_exists` will function correctly since set_exists states that the
object will exist.
:param state: the existence state of the object
:type state: bool
:return:
"""
module = get_calling_module(point=3)
logging.info("Calling module: %s, Setting Exists bit: %s" % (module, state))
self.exists = state
[docs]class PluginResponse(object):
"""
Encapsulating class for holding SEMP requests and their accompanying kwargs.
Example:
>>> request = PluginResponse('<rpc semp-version="soltr/7_1_1"><show><memory/></show></rpc>', primaryOnly=True)
>>> request.xml
'<rpc semp-version="soltr/7_1_1"><show><memory/></show></rpc>'
"""
def __init__(self, xml, **kwargs):
self.xml = xml
""" the XML """
self.kwargs = kwargs
""" the kwargs """