1
0
Fork 0
mirror of https://github.com/yweber/lodel2.git synced 2026-03-14 23:32:02 +01:00

Implements SessionHandlerPlugin ExtensionsPlugin + settings preload

Implements both Plugin child classes handling extensions and session handling.
Modified the settings plugin preload piece of code. It is now adapted to the new plugins organisation.
Each Plugin child classes provides a confspec indicating where the plugin list is stored in configuration.
This commit is contained in:
Yann 2016-08-19 16:21:29 +02:00
commit 76e386e321
14 changed files with 104 additions and 94 deletions

View file

@ -42,3 +42,5 @@
from .hooks import LodelHook
from .plugins import Plugin, CustomMethod
from .datasource_plugin import DatasourcePlugin
from .sessionhandler import SessionHandlerPlugin
from .extensions import Extension

View file

@ -14,9 +14,9 @@ class DatasourcePlugin(Plugin):
##@brief Stores confspecs indicating where DatasourcePlugin list is stored
_plist_confspecs = {
'section': 'lodel2',
'key': 'datasources',
'key': 'datasource_connectors',
'default': None,
'validator': SettingValidator('list', none_is_valid = False) }
'validator': SettingValidator('strip', none_is_valid = False) }
def __init__(self, name):
super().__init__(name)
@ -30,10 +30,6 @@ class DatasourcePlugin(Plugin):
def migration_handler(self):
return self.loader_module().migration_handler_class()
@classmethod
def plist_confspec(cls):
return copy.copy(cls._plist_confspecs)
##@brief Return an initialized Datasource instance
#@param ds_name str : The name of the datasource to instanciate
#@param ro bool

View file

@ -0,0 +1,12 @@
from .plugins import Plugin
from .exceptions import *
from lodel.settings.validator import SettingValidator
class Extension(Plugin):
_plist_confspecs = {
'section': 'lodel2',
'key': 'extensions',
'default': [],
'validator': SettingValidator('list', none_is_valid = False)}

View file

@ -11,6 +11,7 @@ import plugins
from lodel import logger
from lodel.settings.utils import SettingsError
from .exceptions import *
from lodel.exceptions import *
## @package lodel.plugins Lodel2 plugins management
#
@ -161,7 +162,6 @@ class MetaPlugType(type):
#Here we can store all child classes of Plugin
super().__init__(name, bases, attrs)
if len(bases) == 1 and bases[0] == object:
print("Dropped : ", name, bases)
return
self.__register_types()
#list_name= [cls.__name__ for cls in __all_ptypes]
@ -177,6 +177,9 @@ def plug_type_register(cls):
__all_ptypes.append(cls)
logger.info("New child class registered : %s" % cls.__name__)
def all_types():
return copy.copy(__all_ptypes)
##@brief Handle plugins
#
@ -205,6 +208,10 @@ class Plugin(object, metaclass=MetaPlugType):
##@brief Store dict representation of discover cache content
_discover_cache = None
#@brief Designed to store, in child classes, the confspec indicating \
#where plugin list is stored
_plist_confspecs = None
##@brief Plugin class constructor
#
# Called by setting in early stage of lodel2 boot sequence using classmethod
@ -213,7 +220,7 @@ class Plugin(object, metaclass=MetaPlugType):
# @param plugin_name str : plugin name
# @throw PluginError
def __init__(self, plugin_name):
self.started()
self.name = plugin_name
self.path = self.plugin_path(plugin_name)
@ -272,9 +279,9 @@ class Plugin(object, metaclass=MetaPlugType):
#PLUGIN_VERSION_VARNAME in init file is mandatory
self.__version = getattr(self.module, PLUGIN_VERSION_VARNAME)
except AttributeError:
msg = "Error that should not append : no %s found in plugin \
init file. Malformed plugin"
msg %= PLUGIN_VERSION_VARNAME
msg = "Error that should not append while loading plugin '%s': no \
%s found in plugin init file. Malformed plugin"
msg %= (plugin_name, PLUGIN_VERSION_VARNAME)
raise LodelFatalError(msg)
# Load plugin type
@ -459,6 +466,13 @@ name differ from the one found in plugin's init file"
def confspecs(self):
return copy.copy(self.__confspecs)
@classmethod
def plist_confspecs(cls):
if cls._plist_confspecs is None:
raise LodelFatalError('Unitialized _plist_confspecs attribute for \
%s' % cls.__name__)
return copy.copy(cls._plist_confspecs)
##@brief Retrieves plugin list confspecs
#
#This method ask for each Plugin child class the confspecs specifying where
@ -525,7 +539,6 @@ file : '%s'. Running discover again..." % DISCOVER_CACHE_FILENAME)
pcls = DatasourcePlugin
else:
pcls = cls
print(plugin_name, ptype, pcls)
plugin = pcls(plugin_name)
cls._plugin_instances[plugin_name] = plugin
logger.debug("Plugin %s available." % plugin)
@ -550,7 +563,7 @@ file : '%s'. Running discover again..." % DISCOVER_CACHE_FILENAME)
# @return the plugin directory path
@classmethod
def plugin_path(cls, plugin_name):
cls.started()
plist = cls.plugin_list()
if plugin_name not in plist:
raise PluginError("No plugin named '%s' found" % plugin_name)
@ -572,25 +585,10 @@ file : '%s'. Running discover again..." % DISCOVER_CACHE_FILENAME)
#
# This method load path and preload plugins
@classmethod
def start(cls, plugins_directories, plugins):
if cls._plugin_directories is not None:
return
import inspect
self_path = inspect.getsourcefile(Plugin)
default_plugin_path = os.path.abspath(self_path + '../../../../plugins')
if plugins_directories is None:
plugins_directories = list()
plugins_directories += [ default_plugin_path ]
cls._plugin_directories = list(set(plugins_directories))
def start(cls, plugins):
for plugin_name in plugins:
cls.register(plugin_name)
@classmethod
def started(cls, raise_if_not = True):
res = cls._plugin_directories is not None
if raise_if_not and not res:
raise RuntimeError("Class Plugins is not initialized")
@classmethod
def clear(cls):
if cls._plugin_directories is not None:
@ -657,7 +655,7 @@ file : '%s'. Running discover again..." % DISCOVER_CACHE_FILENAME)
##@brief Return a list of child Class Plugin
@classmethod
def plugin_types(cls):
return cls.__all_ptypes
return all_types()
##@brief Attempt to open and load plugin discover cache
#@return discover cache
@ -880,31 +878,3 @@ with %s" % (custom_method._method_name, custom_method))
custom_method.__get_method())
logger.debug(
"Custom method %s added to target" % custom_method)
##@page lodel2_plugins Lodel2 plugins system
#
# @par Plugin structure
#A plugin is a package (a folder containing, at least, an __init__.py file.
#This file should expose multiple things :
# - a CONFSPEC variable containing configuration specifications
# - an _activate() method that returns True if the plugin can be activated (
# optionnal)
#
class SessionHandler(Plugin):
__instance = None
def __init__(self, plugin_name):
if self.__instance is None:
super(Plugin, self).__init__(plugin_name)
self.__instance = True
else:
raise RuntimeError("A SessionHandler Plugin is already plug")
class InterfacePlugin(Plugin):
def __init__(self, plugin_name):
super(Plugin, self).__init__(plugin_name)

View file

@ -17,7 +17,6 @@ class MetaLodelScript(type):
#Here we can store all child classes of LodelScript
super().__init__(name, bases, attrs)
if len(bases) == 1 and bases[0] == object:
print("Dropped : ", name, bases)
return
self.__register_script(name)

View file

@ -0,0 +1,28 @@
from .plugins import Plugin
from .exceptions import *
from lodel.settings.validator import SettingValidator
##@page lodel2_plugins Lodel2 plugins system
#
# @par Plugin structure
#A plugin is a package (a folder containing, at least, an __init__.py file.
#This file should expose multiple things :
# - a CONFSPEC variable containing configuration specifications
# - an _activate() method that returns True if the plugin can be activated (
# optionnal)
#
class SessionHandlerPlugin(Plugin):
__instance = None
_plist_confspecs = {
'section': 'lodel2',
'key': 'session_handler',
'default': None,
'validator': SettingValidator('string', none_is_valid=False)}
def __init__(self, plugin_name):
if self.__instance is None:
super(Plugin, self).__init__(plugin_name)
self.__instance = True
else:
raise RuntimeError("A SessionHandler Plugin is already plug")

View file

@ -11,7 +11,8 @@ from collections import namedtuple
from lodel import logger
from lodel.plugin.plugins import Plugin, PluginError
from lodel.settings.utils import SettingsError, SettingsErrors
from lodel.settings.validator import SettingValidator, LODEL2_CONF_SPECS
from lodel.settings.validator import SettingValidator, LODEL2_CONF_SPECS, \
confspec_append
from lodel.settings.settings_loader import SettingsLoader
## @package lodel.settings.settings Lodel2 settings module
@ -132,6 +133,25 @@ class Settings(object, metaclass=MetaSettings):
def __bootstrap(self):
logger.debug("Settings bootstraping")
lodel2_specs = LODEL2_CONF_SPECS
loader = SettingsLoader(self.__conf_dir)
plugin_list = []
for ptype in Plugin.plugin_types():
pls = ptype.plist_confspecs()
lodel2_specs = confspec_append(lodel2_specs, **pls)
cur_list = loader.getoption(
pls['section'],
pls['key'],
pls['validator'],
pls['default'])
if cur_list is None:
continue
try:
if isinstance(cur_list, str):
cur_list = [cur_list]
plugin_list += cur_list
except TypeError:
plugin_list += [cur_list]
#Checking confspecs
for section in lodel2_specs:
if section.lower() != section:
raise SettingsError("Only lower case are allowed in section name (thank's ConfigParser...)")
@ -139,30 +159,13 @@ class Settings(object, metaclass=MetaSettings):
if kname.lower() != kname:
raise SettingsError("Only lower case are allowed in section name (thank's ConfigParser...)")
# Load specs for the plugins list and plugins_path list conf keys
plugins_opt_specs = lodel2_specs['lodel2']['plugins']
plugins_path_opt_specs = lodel2_specs['lodel2']['plugins_path']
# Init the settings loader
loader = SettingsLoader(self.__conf_dir)
# fetching list of plugins to load
plugins_list = loader.getoption( 'lodel2',
'plugins',
plugins_opt_specs[1],
plugins_opt_specs[0],
False)
plugins_path = loader.getoption( 'lodel2',
'plugins_path',
plugins_path_opt_specs[1],
plugins_path_opt_specs[0],
False)
# Starting the Plugins class
logger.debug("Starting lodel.plugin.Plugin class")
Plugin.start(plugins_path, plugins_list)
Plugin.start(plugin_list)
# Fetching conf specs from plugins
specs = [lodel2_specs]
errors = list()
for plugin_name in plugins_list:
for plugin_name in plugin_list:
try:
specs.append(Plugin.get(plugin_name).confspecs)
except PluginError as e:

View file

@ -66,7 +66,6 @@ class SettingsLoader(object):
# @return the option
def getoption(self,section,keyname,validator,default_value=None,mandatory=False):
conf=self.__conf
if section not in conf:
conf[section] = dict()

View file

@ -357,17 +357,12 @@ SettingValidator.create_re_validator(
#@param orig dict : the confspec to update
#@param upd dict : the confspec to add
#@return new confspec
def confspec_append(orig, upd):
for section in orig:
if section in upd:
orig[section].update(upd[section])
else:
orig[section] = upd[section]
return orig
def confspec_add(orig, section, key, default, validator):
def confspec_append(orig, section, key, validator, default):
if section not in orig:
section[orig] = dict()
orig[section] = dict()
if key not in orig[section]:
orig[section][key] = (default, validator)
return orig
##@brief Global specifications for lodel2 settings
LODEL2_CONF_SPECS = {

View file

@ -1,7 +1,7 @@
from lodel.settings.validator import SettingValidator
__plugin_name__ = 'filesystem_session'
__version = [0,0,1]
__version__ = [0,0,1]
__type__ = 'session_handler'
__loader__ = 'main.py'
__confspec__ = "confspec.py"

View file

@ -4,7 +4,7 @@ from lodel.settings.validator import SettingValidator
CONFSPEC = {
'lodel2.sessions':{
'directory': ('/tmp/lodel2_session', SettingValidator('path')),
'directory': ('/tmp/', SettingValidator('path')),
'expiration': (900, SettingValidator('int')),
'file_template': ('lodel2_%s.sess', SettingValidator('dummy'))
}

View file

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
"""
from lodel.auth.exceptions import AuthenticationError
from lodel.plugin import LodelHook
@ -38,3 +39,4 @@ def read_session(caller, sid):
def clean_sessions(caller):
FileSystemSession.clean()
'''
"""

View file

@ -4,6 +4,7 @@ import unittest
import os.path
from lodel.settings.utils import *
from lodel.plugin.exceptions import *
from lodel.settings.settings_loader import SettingsLoader
@ -255,5 +256,5 @@ class SettingsLoaderTestCase(unittest.TestCase):
def test_invalid_conf(self):
from lodel.settings.settings import Settings
Settings.stop()
with self.assertRaises(SettingsErrors):
with self.assertRaises((SettingsErrors, PluginError)):
Settings('tests/settings/settings_examples/bad_conf.d')

View file

@ -4,6 +4,9 @@ sitename = noname
plugins_path = /foo/plugins
plugins = dummy, dummy_datasource
runtest=True
extensions = dummy
datasource_connectors = dummy_datasource
session_handler = filesystem_session
[lodel2.logging.stderr]
level = Error