mirror of
https://github.com/yweber/lodel2.git
synced 2025-11-22 13:46:54 +01:00
Merge branch 'newlodel' of git.labocleo.org:lodel2 into newlodel
This commit is contained in:
commit
c8a6d5f99a
12 changed files with 192 additions and 119 deletions
|
|
@ -1,7 +0,0 @@
|
||||||
#-*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
import imp
|
|
||||||
import lodel.settings
|
|
||||||
from lodel.settings.settings import Settings
|
|
||||||
Settings.bootstrap(conf_file = 'settings_local.ini', conf_dir = 'globconf.d')
|
|
||||||
imp.reload(lodel.settings)
|
|
||||||
|
|
@ -1 +1,3 @@
|
||||||
__author__ = 'roland'
|
#-*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from .utils.starter import init_lodel
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@ import hashlib
|
||||||
import importlib
|
import importlib
|
||||||
|
|
||||||
from lodel.utils.mlstring import MlString
|
from lodel.utils.mlstring import MlString
|
||||||
|
from lodel.logger import logger
|
||||||
|
from lodel.settings import Settings
|
||||||
|
from lodel.settings.utils import SettingsError
|
||||||
|
|
||||||
from lodel.editorial_model.exceptions import *
|
from lodel.editorial_model.exceptions import *
|
||||||
from lodel.editorial_model.components import EmClass, EmField, EmGroup
|
from lodel.editorial_model.components import EmClass, EmField, EmGroup
|
||||||
|
|
@ -21,13 +24,21 @@ class EditorialModel(object):
|
||||||
self.__groups = dict()
|
self.__groups = dict()
|
||||||
##@brief Stores all classes indexed by id
|
##@brief Stores all classes indexed by id
|
||||||
self.__classes = dict()
|
self.__classes = dict()
|
||||||
|
## @brief Stores all activated groups indexed by id
|
||||||
|
self.__active_groups = dict()
|
||||||
|
## @brief Stores all activated classes indexed by id
|
||||||
|
self.__active_classes = dict()
|
||||||
|
|
||||||
##@brief EmClass accessor
|
##@brief EmClass accessor
|
||||||
# @param uid None | str : give this argument to get a specific EmClass
|
#@param uid None | str : give this argument to get a specific EmClass
|
||||||
# @return if uid is given returns an EmClass else returns an EmClass iterator
|
#@return if uid is given returns an EmClass else returns an EmClass
|
||||||
|
# iterator
|
||||||
|
#@todo use Settings.editorialmodel.groups to determine wich classes should
|
||||||
|
# be returned
|
||||||
def classes(self, uid = None):
|
def classes(self, uid = None):
|
||||||
try:
|
try:
|
||||||
return self.__elt_getter(self.__classes, uid)
|
return self.__elt_getter( self.__active_classes,
|
||||||
|
uid)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise EditorialModelException("EmClass not found : '%s'" % uid)
|
raise EditorialModelException("EmClass not found : '%s'" % uid)
|
||||||
|
|
||||||
|
|
@ -36,10 +47,34 @@ class EditorialModel(object):
|
||||||
# @return if uid is given returns an EmGroup else returns an EmGroup iterator
|
# @return if uid is given returns an EmGroup else returns an EmGroup iterator
|
||||||
def groups(self, uid = None):
|
def groups(self, uid = None):
|
||||||
try:
|
try:
|
||||||
return self.__elt_getter(self.__groups, uid)
|
return self.__elt_getter( self.__active_groups,
|
||||||
|
uid)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
raise EditorialModelException("EmGroup not found : '%s'" % uid)
|
raise EditorialModelException("EmGroup not found : '%s'" % uid)
|
||||||
|
|
||||||
|
##@brief Private getter for __groups or __classes
|
||||||
|
# @see classes() groups()
|
||||||
|
def __elt_getter(self, elts, uid):
|
||||||
|
return list(elts.values()) if uid is None else elts[uid]
|
||||||
|
|
||||||
|
##@brief Update the EditorialModel.__active_groups and
|
||||||
|
#EditorialModel.__active_classes attibutes
|
||||||
|
def __set_actives(self):
|
||||||
|
if Settings.editorialmodel.editormode:
|
||||||
|
# all groups & classes actives because we are in editor mode
|
||||||
|
self.__active_groups = self.__groups
|
||||||
|
self.__active_classes = self.__classes
|
||||||
|
else:
|
||||||
|
#determine groups first
|
||||||
|
self.__active_groups = dict()
|
||||||
|
for agrp in Settings.editorialmodel.groups:
|
||||||
|
if agrp not in self.__groups:
|
||||||
|
raise SettingsError('Invalid group found in settings : %s' % agrp)
|
||||||
|
grp = self.__groups[agrp]
|
||||||
|
self.__active_groups[grp.uid] = grp
|
||||||
|
for acls in grp.components():
|
||||||
|
self.__active_classes[acls.uid] = acls
|
||||||
|
|
||||||
##@brief EmField getter
|
##@brief EmField getter
|
||||||
# @param uid str : An EmField uid represented by "CLASSUID.FIELDUID"
|
# @param uid str : An EmField uid represented by "CLASSUID.FIELDUID"
|
||||||
# @return Fals or an EmField instance
|
# @return Fals or an EmField instance
|
||||||
|
|
@ -65,6 +100,7 @@ class EditorialModel(object):
|
||||||
# @param emclass EmClass : the EmClass instance to add
|
# @param emclass EmClass : the EmClass instance to add
|
||||||
# @return emclass
|
# @return emclass
|
||||||
def add_class(self, emclass):
|
def add_class(self, emclass):
|
||||||
|
self.raise_if_ro()
|
||||||
if not isinstance(emclass, EmClass):
|
if not isinstance(emclass, EmClass):
|
||||||
raise ValueError("<class EmClass> expected but got %s " % type(emclass))
|
raise ValueError("<class EmClass> expected but got %s " % type(emclass))
|
||||||
if emclass.uid in self.classes():
|
if emclass.uid in self.classes():
|
||||||
|
|
@ -76,6 +112,7 @@ class EditorialModel(object):
|
||||||
# @param emgroup EmGroup : the EmGroup instance to add
|
# @param emgroup EmGroup : the EmGroup instance to add
|
||||||
# @return emgroup
|
# @return emgroup
|
||||||
def add_group(self, emgroup):
|
def add_group(self, emgroup):
|
||||||
|
self.raise_if_ro()
|
||||||
if not isinstance(emgroup, EmGroup):
|
if not isinstance(emgroup, EmGroup):
|
||||||
raise ValueError("<class EmGroup> expected but got %s" % type(emgroup))
|
raise ValueError("<class EmGroup> expected but got %s" % type(emgroup))
|
||||||
if emgroup.uid in self.groups():
|
if emgroup.uid in self.groups():
|
||||||
|
|
@ -84,25 +121,36 @@ class EditorialModel(object):
|
||||||
return emgroup
|
return emgroup
|
||||||
|
|
||||||
##@brief Add a new EmClass to the editorial model
|
##@brief Add a new EmClass to the editorial model
|
||||||
# @param uid str : EmClass uid
|
#@param uid str : EmClass uid
|
||||||
# @param **kwargs : EmClass constructor options ( see @ref lodel.editorial_model.component.EmClass.__init__() )
|
#@param **kwargs : EmClass constructor options (
|
||||||
|
# see @ref lodel.editorial_model.component.EmClass.__init__() )
|
||||||
def new_class(self, uid, **kwargs):
|
def new_class(self, uid, **kwargs):
|
||||||
|
self.raise_if_ro()
|
||||||
return self.add_class(EmClass(uid, **kwargs))
|
return self.add_class(EmClass(uid, **kwargs))
|
||||||
|
|
||||||
##@brief Add a new EmGroup to the editorial model
|
##@brief Add a new EmGroup to the editorial model
|
||||||
# @param uid str : EmGroup uid
|
#@param uid str : EmGroup uid
|
||||||
# @param *kwargs : EmGroup constructor keywords arguments (see @ref lodel.editorial_model.component.EmGroup.__init__() )
|
#@param *kwargs : EmGroup constructor keywords arguments (
|
||||||
|
# see @ref lodel.editorial_model.component.EmGroup.__init__() )
|
||||||
def new_group(self, uid, **kwargs):
|
def new_group(self, uid, **kwargs):
|
||||||
|
self.raise_if_ro()
|
||||||
return self.add_group(EmGroup(uid, **kwargs))
|
return self.add_group(EmGroup(uid, **kwargs))
|
||||||
|
|
||||||
# @brief Save a model
|
##@brief Save a model
|
||||||
# @param translator module : The translator module to use
|
# @param translator module : The translator module to use
|
||||||
# @param **translator_args
|
# @param **translator_args
|
||||||
def save(self, translator, **translator_kwargs):
|
def save(self, translator, **translator_kwargs):
|
||||||
|
self.raise_if_ro()
|
||||||
if isinstance(translator, str):
|
if isinstance(translator, str):
|
||||||
translator = self.translator_from_name(translator)
|
translator = self.translator_from_name(translator)
|
||||||
return translator.save(self, **translator_kwargs)
|
return translator.save(self, **translator_kwargs)
|
||||||
|
|
||||||
|
##@brief Raise an error if lodel is not in EM edition mode
|
||||||
|
@staticmethod
|
||||||
|
def raise_if_ro():
|
||||||
|
if not Settings.editorialmodel.editormode:
|
||||||
|
raise EditorialModelError("Lodel in not in EM editor mode. The EM is in read only state")
|
||||||
|
|
||||||
##@brief Load a model
|
##@brief Load a model
|
||||||
# @param translator module : The translator module to use
|
# @param translator module : The translator module to use
|
||||||
# @param **translator_args
|
# @param **translator_args
|
||||||
|
|
@ -125,12 +173,6 @@ class EditorialModel(object):
|
||||||
raise NameError("No translator named %s")
|
raise NameError("No translator named %s")
|
||||||
return mod
|
return mod
|
||||||
|
|
||||||
|
|
||||||
##@brief Private getter for __groups or __classes
|
|
||||||
# @see classes() groups()
|
|
||||||
def __elt_getter(self, elts, uid):
|
|
||||||
return list(elts.values()) if uid is None else elts[uid]
|
|
||||||
|
|
||||||
##@brief Lodel hash
|
##@brief Lodel hash
|
||||||
def d_hash(self):
|
def d_hash(self):
|
||||||
payload = "%s%s" % (
|
payload = "%s%s" % (
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,9 @@ class FieldValidationError(Exception):
|
||||||
##@brief Base class for all data handlers
|
##@brief Base class for all data handlers
|
||||||
class DataHandler(object):
|
class DataHandler(object):
|
||||||
|
|
||||||
__HANDLERS_MODULES = ('datas_base', 'datas', 'references')
|
_HANDLERS_MODULES = ('datas_base', 'datas', 'references')
|
||||||
##@brief Stores the DataHandler childs classes indexed by name
|
##@brief Stores the DataHandler childs classes indexed by name
|
||||||
__base_handlers = None
|
_base_handlers = None
|
||||||
##@brief Stores custom datahandlers classes indexed by name
|
##@brief Stores custom datahandlers classes indexed by name
|
||||||
# @todo do it ! (like plugins, register handlers... blablabla)
|
# @todo do it ! (like plugins, register handlers... blablabla)
|
||||||
__custom_handlers = dict()
|
__custom_handlers = dict()
|
||||||
|
|
@ -132,15 +132,15 @@ class DataHandler(object):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def load_base_handlers(cls):
|
def load_base_handlers(cls):
|
||||||
if cls.__base_handlers is None:
|
if cls._base_handlers is None:
|
||||||
cls.__base_handlers = dict()
|
cls._base_handlers = dict()
|
||||||
for module_name in cls.__HANDLERS_MODULES:
|
for module_name in cls._HANDLERS_MODULES:
|
||||||
module = importlib.import_module('lodel.leapi.datahandlers.%s' % module_name)
|
module = importlib.import_module('lodel.leapi.datahandlers.%s' % module_name)
|
||||||
for name, obj in inspect.getmembers(module):
|
for name, obj in inspect.getmembers(module):
|
||||||
if inspect.isclass(obj):
|
if inspect.isclass(obj):
|
||||||
logger.debug("Load data handler %s.%s" % (obj.__module__, obj.__name__))
|
logger.debug("Load data handler %s.%s" % (obj.__module__, obj.__name__))
|
||||||
cls.__base_handlers[name.lower()] = obj
|
cls._base_handlers[name.lower()] = obj
|
||||||
return copy.copy(cls.__base_handlers)
|
return copy.copy(cls._base_handlers)
|
||||||
|
|
||||||
##@brief given a field type name, returns the associated python class
|
##@brief given a field type name, returns the associated python class
|
||||||
# @param fieldtype_name str : A field type name (not case sensitive)
|
# @param fieldtype_name str : A field type name (not case sensitive)
|
||||||
|
|
@ -149,10 +149,11 @@ class DataHandler(object):
|
||||||
# @note To access custom data handlers it can be cool to preffix the handler name by plugin name for example ? (to ensure name unicity)
|
# @note To access custom data handlers it can be cool to preffix the handler name by plugin name for example ? (to ensure name unicity)
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_name(cls, name):
|
def from_name(cls, name):
|
||||||
|
cls.load_base_handlers()
|
||||||
name = name.lower()
|
name = name.lower()
|
||||||
if name not in cls.__base_handlers:
|
if name not in cls._base_handlers:
|
||||||
raise NameError("No data handlers named '%s'" % (name,))
|
raise NameError("No data handlers named '%s'" % (name,))
|
||||||
return cls.__base_handlers[name]
|
return cls._base_handlers[name]
|
||||||
|
|
||||||
##@brief Return the module name to import in order to use the datahandler
|
##@brief Return the module name to import in order to use the datahandler
|
||||||
# @param data_handler_name str : Data handler name
|
# @param data_handler_name str : Data handler name
|
||||||
|
|
|
||||||
|
|
@ -34,14 +34,5 @@
|
||||||
# </pre>
|
# </pre>
|
||||||
#
|
#
|
||||||
|
|
||||||
|
from lodel.settings.settings import SettingsRO as Settings
|
||||||
import warnings
|
|
||||||
from lodel.settings.settings import Settings as SettingsHandler
|
|
||||||
|
|
||||||
settings = SettingsHandler.instance
|
|
||||||
|
|
||||||
if settings is None:
|
|
||||||
Settings = None
|
|
||||||
else:
|
|
||||||
Settings = settings.confs.lodel2
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,12 @@ PYTHON_SYS_LIB_PATH = '/usr/local/lib/python{major}.{minor}/'.format(
|
||||||
major = sys.version_info.major,
|
major = sys.version_info.major,
|
||||||
minor = sys.version_info.minor)
|
minor = sys.version_info.minor)
|
||||||
|
|
||||||
|
class MetaSettings(type):
|
||||||
|
@property
|
||||||
|
def s(self):
|
||||||
|
self.singleton_assert(True)
|
||||||
|
return self.instance.settings
|
||||||
|
|
||||||
##@brief Handles configuration load etc.
|
##@brief Handles configuration load etc.
|
||||||
#
|
#
|
||||||
# To see howto bootstrap Settings and use it in lodel instance see
|
# To see howto bootstrap Settings and use it in lodel instance see
|
||||||
|
|
@ -61,43 +67,57 @@ PYTHON_SYS_LIB_PATH = '/usr/local/lib/python{major}.{minor}/'.format(
|
||||||
# '.*')
|
# '.*')
|
||||||
# @todo delete the first stage, the lib path HAVE TO BE HARDCODED. In fact
|
# @todo delete the first stage, the lib path HAVE TO BE HARDCODED. In fact
|
||||||
#when we will run lodel in production the lodel2 lib will be in the python path
|
#when we will run lodel in production the lodel2 lib will be in the python path
|
||||||
class Settings(object):
|
class Settings(object, metaclass=MetaSettings):
|
||||||
|
|
||||||
##@brief global conf specsification (default_value + validator)
|
## @brief Stores the singleton instance
|
||||||
_conf_preload = {
|
|
||||||
'lib_path': ( PYTHON_SYS_LIB_PATH+'/lodel2/',
|
|
||||||
SettingValidator('directory')),
|
|
||||||
'plugins_path': ( PYTHON_SYS_LIB_PATH+'lodel2/plugins/',
|
|
||||||
SettingValidator('directory_list')),
|
|
||||||
}
|
|
||||||
instance = None
|
instance = None
|
||||||
|
|
||||||
##@brief Should be called only by the boostrap classmethod
|
## @brief Instanciate the Settings singleton
|
||||||
# @param conf_file str : Path to the global lodel2 configuration file
|
# @param conf_dir str : The configuration directory
|
||||||
# @param conf_dir str : Path to the conf directory
|
def __init__(self, conf_dir):
|
||||||
def __init__(self, conf_file, conf_dir):
|
self.singleton_assert() # check that it is the only instance
|
||||||
self.__confs = dict()
|
Settings.instance = self
|
||||||
|
## @brief Configuration specification
|
||||||
|
#
|
||||||
|
# Initialized by Settings.__bootstrap() method
|
||||||
|
self.__conf_specs = None
|
||||||
|
## @brief Stores the configurations in namedtuple tree
|
||||||
|
self.__confs = None
|
||||||
self.__conf_dir = conf_dir
|
self.__conf_dir = conf_dir
|
||||||
self.__load_bootstrap_conf(conf_file)
|
|
||||||
# now we should have the self.__confs['lodel2']['plugins_paths']
|
|
||||||
# and self.__confs['lodel2']['lib_path'] set
|
|
||||||
self.__bootstrap()
|
self.__bootstrap()
|
||||||
|
|
||||||
##@brief Stores as class attribute a Settings instance
|
## @brief Get the named tuple representing configuration
|
||||||
@classmethod
|
|
||||||
def bootstrap(cls, conf_file = None, conf_dir = None):
|
|
||||||
if cls.instance is None:
|
|
||||||
if conf_file is None and conf_dir is None:
|
|
||||||
warnings.warn("Lodel instance without settings !!!")
|
|
||||||
else:
|
|
||||||
cls.instance = cls(conf_file, conf_dir)
|
|
||||||
return cls.instance
|
|
||||||
|
|
||||||
##@brief Configuration keys accessor
|
|
||||||
# @return All confs organised into named tuples
|
|
||||||
@property
|
@property
|
||||||
def confs(self):
|
def settings(self):
|
||||||
return copy.copy(self.__confs)
|
return self.__confs.lodel2
|
||||||
|
|
||||||
|
## @brief Delete the singleton instance
|
||||||
|
@classmethod
|
||||||
|
def stop(cls):
|
||||||
|
del(cls.instance)
|
||||||
|
cls.instance = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def started(cls):
|
||||||
|
return cls.instance is not None
|
||||||
|
|
||||||
|
##@brief An utility method that raises if the singleton is not in a good
|
||||||
|
# state
|
||||||
|
#@param expect_instanciated bool : if True we expect that the class is
|
||||||
|
# allready instanciated, else not
|
||||||
|
# @throw RuntimeError
|
||||||
|
@classmethod
|
||||||
|
def singleton_assert(cls, expect_instanciated = False):
|
||||||
|
if expect_instanciated:
|
||||||
|
if not cls.started():
|
||||||
|
raise RuntimeError("The Settings class is not started yet")
|
||||||
|
else:
|
||||||
|
if cls.started():
|
||||||
|
raise RuntimeError("The Settings class is allready started")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def set(cls, confname, confvalue):
|
||||||
|
pass
|
||||||
|
|
||||||
##@brief This method handlers Settings instance bootstraping
|
##@brief This method handlers Settings instance bootstraping
|
||||||
def __bootstrap(self):
|
def __bootstrap(self):
|
||||||
|
|
@ -109,15 +129,24 @@ class Settings(object):
|
||||||
if kname.lower() != kname:
|
if kname.lower() != kname:
|
||||||
raise SettingsError("Only lower case are allowed in section name (thank's ConfigParser...)")
|
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_opt_specs = lodel2_specs['lodel2']['plugins']
|
||||||
|
plugins_path_opt_specs = lodel2_specs['lodel2']['plugins_path']
|
||||||
# Init the settings loader
|
# Init the settings loader
|
||||||
loader = SettingsLoader(self.__conf_dir)
|
loader = SettingsLoader(self.__conf_dir)
|
||||||
# fetching list of plugins to load
|
# fetching list of plugins to load
|
||||||
plugins_list = loader.getoption('lodel2', 'plugins', plugins_opt_specs[1], plugins_opt_specs[0], False)
|
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
|
# Starting the Plugins class
|
||||||
Plugins.bootstrap(self.__confs['lodel2']['plugins_path'])
|
Plugins.bootstrap(plugins_path)
|
||||||
# Fetching conf specs from plugins
|
# Fetching conf specs from plugins
|
||||||
specs = [lodel2_specs]
|
specs = [lodel2_specs]
|
||||||
errors = list()
|
errors = list()
|
||||||
|
|
@ -128,8 +157,8 @@ class Settings(object):
|
||||||
errors.append(e)
|
errors.append(e)
|
||||||
if len(errors) > 0: #Raise all plugins import errors
|
if len(errors) > 0: #Raise all plugins import errors
|
||||||
raise SettingsErrors(errors)
|
raise SettingsErrors(errors)
|
||||||
specs = self.__merge_specs(specs)
|
self.__conf_specs = self.__merge_specs(specs)
|
||||||
self.__populate_from_specs(specs, loader)
|
self.__populate_from_specs(self.__conf_specs, loader)
|
||||||
|
|
||||||
##@brief Produce a configuration specification dict by merging all specifications
|
##@brief Produce a configuration specification dict by merging all specifications
|
||||||
#
|
#
|
||||||
|
|
@ -159,6 +188,7 @@ class Settings(object):
|
||||||
# @param specs dict : Settings specification dictionnary as returned by __merge_specs
|
# @param specs dict : Settings specification dictionnary as returned by __merge_specs
|
||||||
# @param loader SettingsLoader : A SettingsLoader instance
|
# @param loader SettingsLoader : A SettingsLoader instance
|
||||||
def __populate_from_specs(self, specs, loader):
|
def __populate_from_specs(self, specs, loader):
|
||||||
|
self.__confs = dict()
|
||||||
specs = copy.copy(specs) #Avoid destroying original specs dict (may be useless)
|
specs = copy.copy(specs) #Avoid destroying original specs dict (may be useless)
|
||||||
# Construct final specs dict replacing variable sections
|
# Construct final specs dict replacing variable sections
|
||||||
# by the actual existing sections
|
# by the actual existing sections
|
||||||
|
|
@ -242,39 +272,11 @@ class Settings(object):
|
||||||
ResNamedTuple = namedtuple(name, conftree.keys())
|
ResNamedTuple = namedtuple(name, conftree.keys())
|
||||||
return ResNamedTuple(**conftree)
|
return ResNamedTuple(**conftree)
|
||||||
|
|
||||||
##@brief Load base global configurations keys
|
class MetaSettingsRO(type):
|
||||||
#
|
def __getattr__(self, name):
|
||||||
# Base configurations keys are :
|
return getattr(Settings.s, name)
|
||||||
# - lodel2 lib path
|
|
||||||
# - lodel2 plugins path
|
|
||||||
#
|
|
||||||
# @note return nothing but set the __confs attribute
|
|
||||||
# @see Settings._conf_preload
|
|
||||||
def __load_bootstrap_conf(self, conf_file):
|
|
||||||
config = configparser.ConfigParser()
|
|
||||||
config.read(conf_file)
|
|
||||||
sections = config.sections()
|
|
||||||
if len(sections) != 1 or sections[0].lower() != 'lodel2':
|
|
||||||
raise SettingsError("Global conf error, expected lodel2 section not found")
|
|
||||||
|
|
||||||
#Load default values in result
|
|
||||||
res = dict()
|
|
||||||
for keyname, (default, _) in self._conf_preload.items():
|
|
||||||
res[keyname] = default
|
|
||||||
|
|
||||||
confs = config[sections[0]]
|
|
||||||
errors = []
|
|
||||||
for name in confs:
|
|
||||||
if name not in res:
|
|
||||||
errors.append( SettingsError(
|
|
||||||
"Unknow field",
|
|
||||||
"lodel2.%s" % name,
|
|
||||||
conf_file))
|
|
||||||
try:
|
|
||||||
res[name] = self._conf_preload[name][1](confs[name])
|
|
||||||
except Exception as e:
|
|
||||||
errors.append(SettingsError(str(e), name, conf_file))
|
|
||||||
if len(errors) > 0:
|
|
||||||
raise SettingsErrors(errors)
|
|
||||||
self.__confs['lodel2'] = res
|
|
||||||
|
|
||||||
|
## @brief A class that provide . notation read only access to configurations
|
||||||
|
class SettingsRO(object, metaclass=MetaSettingsRO):
|
||||||
|
pass
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,10 @@ class SettingsLoader(object):
|
||||||
if keyname in sec:
|
if keyname in sec:
|
||||||
optionstr=sec[keyname]
|
optionstr=sec[keyname]
|
||||||
option=validator(sec[keyname])
|
option=validator(sec[keyname])
|
||||||
del self.__conf_sv[section + ':' + keyname]
|
try:
|
||||||
|
del self.__conf_sv[section + ':' + keyname]
|
||||||
|
except KeyError: #allready fetched
|
||||||
|
pass
|
||||||
return option
|
return option
|
||||||
elif mandatory:
|
elif mandatory:
|
||||||
raise SettingsError("Default value mandatory for option %s" % keyname)
|
raise SettingsError("Default value mandatory for option %s" % keyname)
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,11 @@ def loglevel_val(value):
|
||||||
raise SettingsValidationError("The value '%s' is not a valid loglevel")
|
raise SettingsValidationError("The value '%s' is not a valid loglevel")
|
||||||
return value.upper()
|
return value.upper()
|
||||||
|
|
||||||
|
def path_val(value):
|
||||||
|
if not os.path.exists(value):
|
||||||
|
raise SettingsValidationError("The value '%s' is not a valid path")
|
||||||
|
return value
|
||||||
|
|
||||||
#
|
#
|
||||||
# Default validators registration
|
# Default validators registration
|
||||||
#
|
#
|
||||||
|
|
@ -182,6 +187,11 @@ SettingValidator.register_validator(
|
||||||
loglevel_val,
|
loglevel_val,
|
||||||
'Loglevel validator')
|
'Loglevel validator')
|
||||||
|
|
||||||
|
SettingValidator.register_validator(
|
||||||
|
'path',
|
||||||
|
path_val,
|
||||||
|
'path validator')
|
||||||
|
|
||||||
SettingValidator.create_list_validator(
|
SettingValidator.create_list_validator(
|
||||||
'list',
|
'list',
|
||||||
SettingValidator('strip'),
|
SettingValidator('strip'),
|
||||||
|
|
@ -208,10 +218,14 @@ LODEL2_CONF_SPECS = {
|
||||||
'lodel2': {
|
'lodel2': {
|
||||||
'debug': ( True,
|
'debug': ( True,
|
||||||
SettingValidator('bool')),
|
SettingValidator('bool')),
|
||||||
|
'plugins_path': ( None,
|
||||||
|
SettingValidator('list')),
|
||||||
'plugins': ( "",
|
'plugins': ( "",
|
||||||
SettingValidator('list')),
|
SettingValidator('list')),
|
||||||
'sitename': ( 'noname',
|
'sitename': ( 'noname',
|
||||||
SettingValidator('strip')),
|
SettingValidator('strip')),
|
||||||
|
'lib_path': ( None,
|
||||||
|
SettingValidator('path')),
|
||||||
},
|
},
|
||||||
'lodel2.logging.*' : {
|
'lodel2.logging.*' : {
|
||||||
'level': ( 'ERROR',
|
'level': ( 'ERROR',
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,7 @@
|
||||||
# This file should be imported in every tests files
|
# This file should be imported in every tests files
|
||||||
#
|
#
|
||||||
|
|
||||||
import imp
|
|
||||||
import lodel.settings
|
|
||||||
from lodel.settings.settings import Settings
|
from lodel.settings.settings import Settings
|
||||||
Settings.bootstrap(conf_file = 'settings_local.ini', conf_dir = 'globconf.d')
|
|
||||||
|
|
||||||
imp.reload(lodel.settings)
|
if not Settings.started():
|
||||||
|
Settings('globconf.d')
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
[lodel2.foo.bar]
|
[lodel2.foo.bar]
|
||||||
foo = 42
|
foo = 42
|
||||||
foobar = hello world
|
foobar = hello world
|
||||||
|
foo_bar = foobar
|
||||||
|
foo.bar = barfoo
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
import unittest
|
import unittest
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
|
||||||
|
"""
|
||||||
import tests.loader_utils
|
import tests.loader_utils
|
||||||
from lodel.settings.settings import Settings
|
from lodel.settings.settings import Settings
|
||||||
|
|
||||||
|
|
@ -12,3 +13,4 @@ class SettingsTestCase(unittest.TestCase):
|
||||||
def test_init(self):
|
def test_init(self):
|
||||||
settings = Settings('tests/settings/settings_tests.ini', 'tests/settings/settings_tests_conf.d')
|
settings = Settings('tests/settings/settings_tests.ini', 'tests/settings/settings_tests_conf.d')
|
||||||
pass
|
pass
|
||||||
|
"""
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,29 @@ class SettingsLoaderTestCase(unittest.TestCase):
|
||||||
self.assertEqual(value, "42")
|
self.assertEqual(value, "42")
|
||||||
value = loader.getoption('lodel2.foo.bar', 'foobar', dummy_validator)
|
value = loader.getoption('lodel2.foo.bar', 'foobar', dummy_validator)
|
||||||
self.assertEqual(value, "hello world")
|
self.assertEqual(value, "hello world")
|
||||||
|
value = loader.getoption('lodel2.foo.bar', 'foo_bar', dummy_validator)
|
||||||
|
self.assertEqual(value, "foobar")
|
||||||
|
value = loader.getoption('lodel2.foo.bar', 'foo.bar', dummy_validator)
|
||||||
|
self.assertEqual(value, "barfoo")
|
||||||
|
|
||||||
|
def test_getoption_multiple_time(self):
|
||||||
|
""" Testing the behavior when doing 2 time the same call to getoption """
|
||||||
|
loader = SettingsLoader('tests/settings/settings_examples/simple.conf.d')
|
||||||
|
value = loader.getoption('lodel2.foo.bar', 'foo', dummy_validator)
|
||||||
|
value = loader.getoption('lodel2.foo.bar', 'foo', dummy_validator)
|
||||||
|
value = loader.getoption('lodel2.foo.bar', 'foo', dummy_validator)
|
||||||
|
value = loader.getoption('lodel2.foo.bar', 'foo', dummy_validator)
|
||||||
|
|
||||||
|
|
||||||
|
def test_geoption_default_value(self):
|
||||||
|
""" Testing behavior of default value in getoption """
|
||||||
|
loader = SettingsLoader('tests/settings/settings_examples/simple.conf.d')
|
||||||
|
# for non existing keys in file
|
||||||
|
value = loader.getoption('lodel2.foo.bar', 'foofoofoo', dummy_validator, 'hello 42', False)
|
||||||
|
self.assertEqual(value, 'hello 42')
|
||||||
|
# for non existing section in file
|
||||||
|
value = loader.getoption('lodel2.foofoo', 'foofoofoo', dummy_validator, 'hello 42', False)
|
||||||
|
self.assertEqual(value, 'hello 42')
|
||||||
|
|
||||||
def test_getoption_complex(self):
|
def test_getoption_complex(self):
|
||||||
""" Testing behavior of getoption with less simple files & confs """
|
""" Testing behavior of getoption with less simple files & confs """
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue