From 08ad11624d15b2a35eac6c88a4a53700d250f472 Mon Sep 17 00:00:00 2001 From: prieto Date: Fri, 3 Feb 2017 11:09:52 +0100 Subject: [PATCH] Class Validator replaces SettingValidator --- lodel/leapi/datahandlers/validator.py | 42 ----- lodel/plugin/datasource_plugin.py | 12 +- lodel/plugin/extensions.py | 4 +- lodel/plugin/interface.py | 4 +- lodel/plugin/sessionhandler.py | 4 +- lodel/plugins/dummy/__init__.py | 2 +- lodel/plugins/dummy/confspec.py | 4 +- lodel/plugins/dummy_datasource/__init__.py | 4 +- lodel/plugins/filesystem_session/__init__.py | 2 +- lodel/plugins/filesystem_session/confspec.py | 8 +- lodel/plugins/mongodb_datasource/confspec.py | 14 +- lodel/plugins/multisite/__init__.py | 6 +- lodel/plugins/multisite/confspecs.py | 30 ++-- lodel/plugins/ram_sessions/__init__.py | 6 +- lodel/plugins/webui/confspec.py | 26 +-- lodel/settings/settings.py | 2 +- lodel/settings/settings_loader.py | 2 +- lodel/settings/validator.py | 166 ------------------- lodel/validator/validator.py | 121 ++++++++++++++ scripts/settings_validator.py | 4 +- tests/settings/test_validator.py | 28 ++-- 21 files changed, 202 insertions(+), 289 deletions(-) delete mode 100644 lodel/leapi/datahandlers/validator.py diff --git a/lodel/leapi/datahandlers/validator.py b/lodel/leapi/datahandlers/validator.py deleted file mode 100644 index a30b0a0..0000000 --- a/lodel/leapi/datahandlers/validator.py +++ /dev/null @@ -1,42 +0,0 @@ -#-*- coding: utf-8 -*- - -import sys - -from lodel.context import LodelContext -LodelContext.expose_modules(globals(), { - 'lodel.exceptions': ['LodelException', 'LodelExceptions', - 'LodelFatalError', 'FieldValidationError'], - 'lodel.validator.validator': ['Validator', 'ValidationError']}) - -## @package lodel.DhOptions.validator Lodel2 DhOptions validators/cast module -# -# Validator are registered in the DhOptionValidator class. -# @note to get a list of registered default validators just run -#
$ python scripts/DhOptions_validator.py
- -##@brief Exception class that should be raised when a validation fails -class DhOptionValidationError(ValidationError): - pass - -##@brief Handles DhOptions validators -# -# Class instance are callable objects that takes a value argument (the value to validate). It raises -# a DhOptionsValidationError if validation fails, else it returns a properly -# casted value. -#@todo implement an IP validator and use it in multisite confspec -class DhOptionValidator(Validator): - - ##@brief Instanciate a validator - #@param name str : validator name - #@param none_is_valid bool : if True None will be validated - #@param **kwargs : more arguement for the validator - def __init__(self, name, none_is_valid = False, **kwargs): - super().__init__(name, none_is_valid = False, **kwargs) - - ##@brief Call the validator - # @param value * - # @return properly casted value - # @throw DhOptionsValidationError - def __call__(self, value): - super().__call__(value) - diff --git a/lodel/plugin/datasource_plugin.py b/lodel/plugin/datasource_plugin.py index cf520c8..024224a 100644 --- a/lodel/plugin/datasource_plugin.py +++ b/lodel/plugin/datasource_plugin.py @@ -3,7 +3,7 @@ LodelContext.expose_modules(globals(), { 'lodel.plugin.plugins': ['Plugin'], 'lodel.plugin.exceptions': ['PluginError', 'PluginTypeError', 'LodelScriptError', 'DatasourcePluginError'], - 'lodel.settings.validator': ['SettingValidator'], + 'lodel.validator.validator': ['Validator'], 'lodel.exceptions': ['LodelException', 'LodelExceptions', 'LodelFatalError', 'DataNoneValid', 'FieldValidationError']}) @@ -97,7 +97,7 @@ class DatasourcePlugin(Plugin): 'section': 'lodel2', 'key': 'datasource_connectors', 'default': 'dummy_datasource', - 'validator': SettingValidator( + 'validator': Validator( 'custom_list', none_is_valid = False, validator_name = 'plugin', validator_kwargs = { 'ptype': _glob_typename, @@ -280,13 +280,13 @@ but %s is a %s" % (ds_name, pinstance.__class__.__name__)) #CONFSPEC = { # 'lodel2.datasource.mysql.*' : { # 'host': ( 'localhost', -# SettingValidator('host')), +# Validator('host')), # 'db_name': ( 'lodel', -# SettingValidator('string')), +# Validator('string')), # 'username': ( None, -# SettingValidator('string')), +# Validator('string')), # 'password': ( None, -# SettingValidator('string')), +# Validator('string')), # } #} # diff --git a/lodel/plugin/extensions.py b/lodel/plugin/extensions.py index 9672c90..4c9c098 100644 --- a/lodel/plugin/extensions.py +++ b/lodel/plugin/extensions.py @@ -3,7 +3,7 @@ LodelContext.expose_modules(globals(), { 'lodel.plugin.plugins': ['Plugin'], 'lodel.plugin.exceptions': ['PluginError', 'PluginTypeError', 'LodelScriptError', 'DatasourcePluginError'], - 'lodel.settings.validator': ['SettingValidator']}) + 'lodel.validator.validator': ['Validator']}) _glob_typename = 'extension' @@ -14,7 +14,7 @@ class Extension(Plugin): 'section': 'lodel2', 'key': 'extensions', 'default': None, - 'validator': SettingValidator( + 'validator': Validator( 'custom_list', none_is_valid = True, validator_name = 'plugin', validator_kwargs = { 'ptype': _glob_typename, diff --git a/lodel/plugin/interface.py b/lodel/plugin/interface.py index 04d1a1b..feb0aac 100644 --- a/lodel/plugin/interface.py +++ b/lodel/plugin/interface.py @@ -3,7 +3,7 @@ LodelContext.expose_modules(globals(), { 'lodel.plugin.plugins': ['Plugin'], 'lodel.plugin.exceptions': ['PluginError', 'PluginTypeError', 'LodelScriptError', 'DatasourcePluginError'], - 'lodel.settings.validator': ['SettingValidator']}) + 'lodel.validator.validator': ['Validator']}) _glob_typename = 'ui' @@ -19,7 +19,7 @@ class InterfacePlugin(Plugin): 'section': 'lodel2', 'key': 'interface', 'default': None, - 'validator': SettingValidator( + 'validator': Validator( 'plugin', none_is_valid = True, ptype = _glob_typename)} _type_conf_name = _glob_typename diff --git a/lodel/plugin/sessionhandler.py b/lodel/plugin/sessionhandler.py index 5333fd2..4ad19df 100644 --- a/lodel/plugin/sessionhandler.py +++ b/lodel/plugin/sessionhandler.py @@ -3,7 +3,7 @@ LodelContext.expose_modules(globals(), { 'lodel.plugin.plugins': ['Plugin', 'MetaPlugType'], 'lodel.plugin.exceptions': ['PluginError', 'PluginTypeError', 'LodelScriptError', 'DatasourcePluginError'], - 'lodel.settings.validator': ['SettingValidator']}) + 'lodel.validator.validator': ['Validator']}) ##@brief SessionHandlerPlugin metaclass designed to implements a wrapper @@ -53,7 +53,7 @@ class SessionHandlerPlugin(Plugin, metaclass=SessionPluginWrapper): 'section': 'lodel2', 'key': 'session_handler', 'default': None, - 'validator': SettingValidator( + 'validator': Validator( 'plugin', none_is_valid=False,ptype = _glob_typename)} _type_conf_name = _glob_typename diff --git a/lodel/plugins/dummy/__init__.py b/lodel/plugins/dummy/__init__.py index c0b6786..fe04298 100644 --- a/lodel/plugins/dummy/__init__.py +++ b/lodel/plugins/dummy/__init__.py @@ -1,6 +1,6 @@ from lodel.context import LodelContext LodelContext.expose_modules(globals(), { - 'lodel.settings.validator': ['SettingValidator']}) + 'lodel.validator.validator': ['Validator']}) __plugin_name__ = "dummy" __version__ = '0.0.1' #or __version__ = [0,0,1] diff --git a/lodel/plugins/dummy/confspec.py b/lodel/plugins/dummy/confspec.py index 9d9dba2..e9e7e35 100644 --- a/lodel/plugins/dummy/confspec.py +++ b/lodel/plugins/dummy/confspec.py @@ -2,11 +2,11 @@ from lodel.context import LodelContext LodelContext.expose_modules(globals(), { - 'lodel.settings.validator': ['SettingValidator']}) + 'lodel.validator.validator': ['Validator']}) CONFSPEC = { 'lodel2.section1': { 'key1': ( None, - SettingValidator('dummy')) + Validator('dummy')) } } diff --git a/lodel/plugins/dummy_datasource/__init__.py b/lodel/plugins/dummy_datasource/__init__.py index 4934325..7b0ca83 100644 --- a/lodel/plugins/dummy_datasource/__init__.py +++ b/lodel/plugins/dummy_datasource/__init__.py @@ -1,6 +1,6 @@ from lodel.context import LodelContext LodelContext.expose_modules(globals(), { - 'lodel.settings.validator': ['SettingValidator']}) + 'lodel.validator.validator': ['Validator']}) from .datasource import DummyDatasource as Datasource __plugin_type__ = 'datasource' @@ -12,7 +12,7 @@ __plugin_deps__ = [] CONFSPEC = { 'lodel2.datasource.dummy_datasource.*' : { 'dummy': ( None, - SettingValidator('dummy'))} + Validator('dummy'))} } diff --git a/lodel/plugins/filesystem_session/__init__.py b/lodel/plugins/filesystem_session/__init__.py index bbb2ffb..ae430e7 100644 --- a/lodel/plugins/filesystem_session/__init__.py +++ b/lodel/plugins/filesystem_session/__init__.py @@ -1,6 +1,6 @@ from lodel.context import LodelContext LodelContext.expose_modules(globals(), { - 'lodel.settings.validator': ['SettingValidator']}) + 'lodel.validator.validator': ['Validator']}) __plugin_name__ = 'filesystem_session' __version__ = [0,0,1] diff --git a/lodel/plugins/filesystem_session/confspec.py b/lodel/plugins/filesystem_session/confspec.py index c8da6a4..6ae7059 100644 --- a/lodel/plugins/filesystem_session/confspec.py +++ b/lodel/plugins/filesystem_session/confspec.py @@ -2,12 +2,12 @@ from lodel.context import LodelContext LodelContext.expose_modules(globals(), { - 'lodel.settings.validator': ['SettingValidator']}) + 'lodel.validator.validator': ['Validator']}) CONFSPEC = { 'lodel2.sessions':{ - 'directory': ('/tmp/', SettingValidator('path')), - 'expiration': (900, SettingValidator('int')), - 'file_template': ('lodel2_%s.sess', SettingValidator('dummy')) + 'directory': ('/tmp/', Validator('path')), + 'expiration': (900, Validator('int')), + 'file_template': ('lodel2_%s.sess', Validator('dummy')) } } diff --git a/lodel/plugins/mongodb_datasource/confspec.py b/lodel/plugins/mongodb_datasource/confspec.py index feabcc4..945c8c9 100644 --- a/lodel/plugins/mongodb_datasource/confspec.py +++ b/lodel/plugins/mongodb_datasource/confspec.py @@ -2,7 +2,7 @@ from lodel.context import LodelContext LodelContext.expose_modules(globals(), { - 'lodel.settings.validator': ['SettingValidator']}) + 'lodel.validator.validator': ['Validator']}) ##@brief Mongodb datasource plugin confspec #@ingroup plugin_mongodb_datasource @@ -10,11 +10,11 @@ LodelContext.expose_modules(globals(), { #Describe mongodb plugin configuration. Keys are : CONFSPEC = { 'lodel2.datasource.mongodb_datasource.*':{ - 'read_only': (False, SettingValidator('bool')), - 'host': ('localhost', SettingValidator('host')), - 'port': (None, SettingValidator('string', none_is_valid = True)), - 'db_name':('lodel', SettingValidator('string')), - 'username': (None, SettingValidator('string')), - 'password': (None, SettingValidator('string')) + 'read_only': (False, Validator('bool')), + 'host': ('localhost', Validator('host')), + 'port': (None, Validator('string', none_is_valid = True)), + 'db_name':('lodel', Validator('string')), + 'username': (None, Validator('string')), + 'password': (None, Validator('string')) } } diff --git a/lodel/plugins/multisite/__init__.py b/lodel/plugins/multisite/__init__.py index 6a5e7fe..6d3d50a 100644 --- a/lodel/plugins/multisite/__init__.py +++ b/lodel/plugins/multisite/__init__.py @@ -1,7 +1,7 @@ from lodel.context import LodelContext, ContextError try: LodelContext.expose_modules(globals(), { - 'lodel.settings.validator': ['SettingValidator']}) + 'lodel.validator.validator': ['Validator']}) __plugin_name__ = "multisite" __version__ = '0.0.1' #or __version__ = [0,0,1] @@ -13,8 +13,8 @@ try: CONFSPEC = { 'lodel2.server': { - 'port': (80,SettingValidator('int')), - 'listen_addr': ('', SettingValidator('string')), + 'port': (80,Validator('int')), + 'listen_addr': ('', Validator('string')), } } diff --git a/lodel/plugins/multisite/confspecs.py b/lodel/plugins/multisite/confspecs.py index a8c8408..6015b57 100644 --- a/lodel/plugins/multisite/confspecs.py +++ b/lodel/plugins/multisite/confspecs.py @@ -1,34 +1,34 @@ from lodel.context import LodelContext LodelContext.expose_modules(globals(), { - 'lodel.settings.validator': ['SettingValidator']}) + 'lodel.validator.validator': ['Validator']}) #Define a minimal confspec used by multisite loader LODEL2_CONFSPECS = { 'lodel2': { - 'debug': (True, SettingValidator('bool')) + 'debug': (True, Validator('bool')) }, 'lodel2.server': { - 'listen_address': ('127.0.0.1', SettingValidator('dummy')), - #'listen_address': ('', SettingValidator('ip')), #<-- not implemented - 'listen_port': ( 1337, SettingValidator('int')), - 'uwsgi_workers': (8, SettingValidator('int')), - 'uwsgicmd': ('/usr/bin/uwsgi', SettingValidator('dummy')), - 'virtualenv': (None, SettingValidator('path', none_is_valid = True)), + 'listen_address': ('127.0.0.1', Validator('dummy')), + #'listen_address': ('', Validator('ip')), #<-- not implemented + 'listen_port': ( 1337, Validator('int')), + 'uwsgi_workers': (8, Validator('int')), + 'uwsgicmd': ('/usr/bin/uwsgi', Validator('dummy')), + 'virtualenv': (None, Validator('path', none_is_valid = True)), }, 'lodel2.logging.*' : { 'level': ( 'ERROR', - SettingValidator('loglevel')), + Validator('loglevel')), 'context': ( False, - SettingValidator('bool')), + Validator('bool')), 'filename': ( None, - SettingValidator('errfile', none_is_valid = True)), + Validator('errfile', none_is_valid = True)), 'backupcount': ( 10, - SettingValidator('int', none_is_valid = False)), + Validator('int', none_is_valid = False)), 'maxbytes': ( 1024*10, - SettingValidator('int', none_is_valid = False)), + Validator('int', none_is_valid = False)), }, 'lodel2.datasources.*': { - 'read_only': (False, SettingValidator('bool')), - 'identifier': ( None, SettingValidator('string')), + 'read_only': (False, Validator('bool')), + 'identifier': ( None, Validator('string')), } } diff --git a/lodel/plugins/ram_sessions/__init__.py b/lodel/plugins/ram_sessions/__init__.py index 8d580c4..536bd25 100644 --- a/lodel/plugins/ram_sessions/__init__.py +++ b/lodel/plugins/ram_sessions/__init__.py @@ -1,6 +1,6 @@ from lodel.context import LodelContext LodelContext.expose_modules(globals(), { - 'lodel.settings.validator': ['SettingValidator']}) + 'lodel.validator.validator': ['Validator']}) __plugin_name__ = 'ram_sessions' __version__ = [0,0,1] @@ -11,7 +11,7 @@ __fullname__ = "RAM Session Store Plugin" CONFSPEC = { 'lodel2.sessions':{ - 'expiration': (900, SettingValidator('int')), - 'tokensize': (512, SettingValidator('int')), + 'expiration': (900, Validator('int')), + 'tokensize': (512, Validator('int')), } } diff --git a/lodel/plugins/webui/confspec.py b/lodel/plugins/webui/confspec.py index b1cdded..5c1abfc 100644 --- a/lodel/plugins/webui/confspec.py +++ b/lodel/plugins/webui/confspec.py @@ -1,30 +1,30 @@ from lodel.context import LodelContext LodelContext.expose_modules(globals(), { - 'lodel.settings.validator': ['SettingValidator']}) + 'lodel.validator.validator': ['Validator']}) CONFSPEC = { 'lodel2.webui': { 'standalone': ( 'False', - SettingValidator('string')), + Validator('string')), 'listen_address': ( '127.0.0.1', - SettingValidator('dummy')), + Validator('dummy')), 'listen_port': ( '9090', - SettingValidator('int')), + Validator('int')), 'static_url': ( 'http://127.0.0.1/static/', - SettingValidator('regex', pattern = r'^https?://[^/].*$')), + Validator('regex', pattern = r'^https?://[^/].*$')), 'virtualenv': (None, - SettingValidator('path', none_is_valid=True)), - 'uwsgicmd': ('/usr/bin/uwsgi', SettingValidator('dummy')), - 'cookie_secret_key': ('ConfigureYourOwnCookieSecretKey', SettingValidator('dummy')), - 'cookie_session_id': ('lodel', SettingValidator('dummy')), - 'uwsgi_workers': (2, SettingValidator('int')) + Validator('path', none_is_valid=True)), + 'uwsgicmd': ('/usr/bin/uwsgi', Validator('dummy')), + 'cookie_secret_key': ('ConfigureYourOwnCookieSecretKey', Validator('dummy')), + 'cookie_session_id': ('lodel', Validator('dummy')), + 'uwsgi_workers': (2, Validator('int')) }, 'lodel2.webui.sessions': { 'directory': ( '/tmp', - SettingValidator('path')), + Validator('path')), 'expiration': ( 900, - SettingValidator('int')), + Validator('int')), 'file_template': ( 'lodel2_%s.sess', - SettingValidator('dummy')), + Validator('dummy')), } } diff --git a/lodel/settings/settings.py b/lodel/settings/settings.py index bec2f8b..662b602 100644 --- a/lodel/settings/settings.py +++ b/lodel/settings/settings.py @@ -13,7 +13,7 @@ from lodel.context import LodelContext LodelContext.expose_modules(globals(),{ 'lodel.logger': 'logger', 'lodel.settings.utils': ['SettingsError', 'SettingsErrors'], - 'lodel.settings.validator': ['SettingValidator', 'LODEL2_CONF_SPECS', + 'lodel.validator.validator': ['Validator', 'LODEL2_CONF_SPECS', 'confspec_append'], 'lodel.settings.settings_loader':['SettingsLoader']}) diff --git a/lodel/settings/settings_loader.py b/lodel/settings/settings_loader.py index 587a6ae..77c3656 100644 --- a/lodel/settings/settings_loader.py +++ b/lodel/settings/settings_loader.py @@ -9,7 +9,7 @@ from lodel.context import LodelContext LodelContext.expose_modules(globals(), { 'lodel.logger': 'logger', 'lodel.settings.utils': ['SettingsError', 'SettingsErrors'], - 'lodel.settings.validator': ['SettingValidationError']}) + 'lodel.validator.validator': ['ValidationError']}) ##@brief Merges and loads configuration files class SettingsLoader(object): diff --git a/lodel/settings/validator.py b/lodel/settings/validator.py index 554ab9c..652f2c0 100644 --- a/lodel/settings/validator.py +++ b/lodel/settings/validator.py @@ -1,169 +1,3 @@ #-*- coding: utf-8 -*- -import sys -import os.path -import re -import socket -import inspect -import copy -from lodel.context import LodelContext -LodelContext.expose_modules(globals(), { - 'lodel.exceptions': ['LodelException', 'LodelExceptions', - 'LodelFatalError', 'FieldValidationError'], - 'lodel.validator.validator': ['Validator', 'ValidationError']}) - -## @package lodel.settings.validator Lodel2 settings validators/cast module -# -# Validator are registered in the SettingValidator class. -# @note to get a list of registered default validators just run -#
$ python scripts/settings_validator.py
- -##@brief Exception class that should be raised when a validation fails -class SettingValidationError(ValidationError): - pass - -##@brief Handles settings validators -# -# Class instance are callable objects that takes a value argument (the value to validate). It raises -# a SettingsValidationError if validation fails, else it returns a properly -# casted value. -#@todo implement an IP validator and use it in multisite confspec -class SettingValidator(Validator): - - ##@brief Instanciate a validator - #@param name str : validator name - #@param none_is_valid bool : if True None will be validated - #@param **kwargs : more arguement for the validator - def __init__(self, name, none_is_valid = False, **kwargs): - super().__init__(name, none_is_valid = False, **kwargs) - - ##@brief Call the validator - # @param value * - # @return properly casted value - # @throw SettingsValidationError - def __call__(self, value): - super().__call__(value) - -##@brief Validator for Editorial model component -# -# Designed to validate a conf that indicate a class.field in an EM -#@todo modified the hardcoded dyncode import (it's a warning) -def emfield_val(value): - LodelContext.expose_modules(globals(), { - 'lodel.plugin.hooks': ['LodelHook']}) - spl = value.split('.') - if len(spl) != 2: - msg = "Expected a value in the form CLASSNAME.FIELDNAME but got : %s" - raise SettingsValidationError(msg % value) - value = tuple(spl) - #Late validation hook - @LodelHook('lodel2_dyncode_bootstraped') - def emfield_conf_check(hookname, caller, payload): - import leapi_dyncode as dyncode # <-- dirty & quick - classnames = { cls.__name__.lower():cls for cls in dyncode.dynclasses} - if value[0].lower() not in classnames: - msg = "Following dynamic class do not exists in current EM : %s" - raise SettingsValidationError(msg % value[0]) - ccls = classnames[value[0].lower()] - if value[1].lower() not in ccls.fieldnames(True): - msg = "Following field not found in class %s : %s" - raise SettingsValidationError(msg % value) - return value - -##@brief Validator for plugin name & optionnaly type -# -#Able to check that the value is a plugin and if it is of a specific type -def plugin_validator(value, ptype = None): - LodelContext.expose_modules(globals(), { - 'lodel.plugin.hooks': ['LodelHook']}) - value = copy.copy(value) - @LodelHook('lodel2_dyncode_bootstraped') - def plugin_type_checker(hookname, caller, payload): - LodelContext.expose_modules(globals(), { - 'lodel.plugin.plugins': ['Plugin'], - 'lodel.plugin.exceptions': ['PluginError']}) - if value is None: - return - try: - plugin = Plugin.get(value) - except PluginError: - msg = "No plugin named %s found" - msg %= value - raise SettingsValidationError(msg) - if plugin._type_conf_name.lower() != ptype.lower(): - msg = "A plugin of type '%s' was expected but found a plugin \ -named '%s' that is a '%s' plugin" - msg %= (ptype, value, plugin._type_conf_name) - raise SettingsValidationError(msg) - return value - - - -SettingValidator.register_validator( - 'plugin', - plugin_validator, - 'plugin name & type validator') - -SettingValidator.register_validator( - 'emfield', - emfield_val, - 'EmField name validator') - -# -# Lodel 2 configuration specification -# - -##@brief Append a piece of confspec -#@note orig is modified during the process -#@param orig dict : the confspec to update -#@param section str : section name -#@param key str -#@param validator SettingValidator : the validator to use to check this configuration key's value -#@param default -#@return new confspec -def confspec_append(orig, section, key, validator, default): - if section not in orig: - 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 = { - 'lodel2': { - 'debug': ( True, - SettingValidator('bool')), - 'sitename': ( 'noname', - SettingValidator('strip')), - 'runtest': ( False, - SettingValidator('bool')), - }, - 'lodel2.logging.*' : { - 'level': ( 'ERROR', - SettingValidator('loglevel')), - 'context': ( False, - SettingValidator('bool')), - 'filename': ( "-", - SettingValidator('errfile', none_is_valid = False)), - 'backupcount': ( 5, - SettingValidator('int', none_is_valid = False)), - 'maxbytes': ( 1024*10, - SettingValidator('int', none_is_valid = False)), - }, - 'lodel2.editorialmodel': { - 'emfile': ( 'em.pickle', SettingValidator('strip')), - 'emtranslator': ( 'picklefile', SettingValidator('strip')), - 'dyncode': ( 'leapi_dyncode.py', SettingValidator('strip')), - 'groups': ( '', SettingValidator('list')), - 'editormode': ( False, SettingValidator('bool')), - }, - 'lodel2.datasources.*': { - 'read_only': (False, SettingValidator('bool')), - 'identifier': ( None, SettingValidator('string')), - }, - 'lodel2.auth': { - 'login_classfield': ('user.login', SettingValidator('emfield')), - 'pass_classfield': ('user.password', SettingValidator('emfield')), - }, -} diff --git a/lodel/validator/validator.py b/lodel/validator/validator.py index 6272ed8..301eab3 100644 --- a/lodel/validator/validator.py +++ b/lodel/validator/validator.py @@ -341,3 +341,124 @@ Validator.create_re_validator( r'^https?://[^\./]+.[^\./]+/?.*$', 'http_url', 'Url validator') +##@brief Validator for Editorial model component +# +# Designed to validate a conf that indicate a class.field in an EM +#@todo modified the hardcoded dyncode import (it's a warning) +def emfield_val(value): + LodelContext.expose_modules(globals(), { + 'lodel.plugin.hooks': ['LodelHook']}) + spl = value.split('.') + if len(spl) != 2: + msg = "Expected a value in the form CLASSNAME.FIELDNAME but got : %s" + raise SettingsValidationError(msg % value) + value = tuple(spl) + #Late validation hook + @LodelHook('lodel2_dyncode_bootstraped') + def emfield_conf_check(hookname, caller, payload): + import leapi_dyncode as dyncode # <-- dirty & quick + classnames = { cls.__name__.lower():cls for cls in dyncode.dynclasses} + if value[0].lower() not in classnames: + msg = "Following dynamic class do not exists in current EM : %s" + raise SettingsValidationError(msg % value[0]) + ccls = classnames[value[0].lower()] + if value[1].lower() not in ccls.fieldnames(True): + msg = "Following field not found in class %s : %s" + raise SettingsValidationError(msg % value) + return value + +##@brief Validator for plugin name & optionnaly type +# +#Able to check that the value is a plugin and if it is of a specific type +def plugin_validator(value, ptype = None): + LodelContext.expose_modules(globals(), { + 'lodel.plugin.hooks': ['LodelHook']}) + value = copy.copy(value) + @LodelHook('lodel2_dyncode_bootstraped') + def plugin_type_checker(hookname, caller, payload): + LodelContext.expose_modules(globals(), { + 'lodel.plugin.plugins': ['Plugin'], + 'lodel.plugin.exceptions': ['PluginError']}) + if value is None: + return + try: + plugin = Plugin.get(value) + except PluginError: + msg = "No plugin named %s found" + msg %= value + raise ValidationError(msg) + if plugin._type_conf_name.lower() != ptype.lower(): + msg = "A plugin of type '%s' was expected but found a plugin \ +named '%s' that is a '%s' plugin" + msg %= (ptype, value, plugin._type_conf_name) + raise ValidationError(msg) + return value + + +Validator.register_validator( + 'plugin', + plugin_validator, + 'plugin name & type validator') + +Validator.register_validator( + 'emfield', + emfield_val, + 'EmField name validator') + +# +# Lodel 2 configuration specification +# + +##@brief Append a piece of confspec +#@note orig is modified during the process +#@param orig dict : the confspec to update +#@param section str : section name +#@param key str +#@param validator Validator : the validator to use to check this configuration key's value +#@param default +#@return new confspec +def confspec_append(orig, section, key, validator, default): + if section not in orig: + 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 = { + 'lodel2': { + 'debug': ( True, + Validator('bool')), + 'sitename': ( 'noname', + Validator('strip')), + 'runtest': ( False, + Validator('bool')), + }, + 'lodel2.logging.*' : { + 'level': ( 'ERROR', + Validator('loglevel')), + 'context': ( False, + Validator('bool')), + 'filename': ( "-", + Validator('errfile', none_is_valid = False)), + 'backupcount': ( 5, + Validator('int', none_is_valid = False)), + 'maxbytes': ( 1024*10, + Validator('int', none_is_valid = False)), + }, + 'lodel2.editorialmodel': { + 'emfile': ( 'em.pickle', Validator('strip')), + 'emtranslator': ( 'picklefile', Validator('strip')), + 'dyncode': ( 'leapi_dyncode.py', Validator('strip')), + 'groups': ( '', Validator('list')), + 'editormode': ( False, Validator('bool')), + }, + 'lodel2.datasources.*': { + 'read_only': (False, Validator('bool')), + 'identifier': ( None, Validator('string')), + }, + 'lodel2.auth': { + 'login_classfield': ('user.login', Validator('emfield')), + 'pass_classfield': ('user.password', Validator('emfield')), + }, +} \ No newline at end of file diff --git a/scripts/settings_validator.py b/scripts/settings_validator.py index a810cb2..dde5685 100644 --- a/scripts/settings_validator.py +++ b/scripts/settings_validator.py @@ -2,5 +2,5 @@ import sys import os, os.path sys.path.append(os.path.dirname(os.getcwd()+'/..')) -from lodel.settings.validator import SettingValidator -print(SettingValidator.validators_list_str()) +from lodel.validator.validator import Validator +print(Validator.validators_list_str()) diff --git a/tests/settings/test_validator.py b/tests/settings/test_validator.py index d24a8b1..fc283a2 100644 --- a/tests/settings/test_validator.py +++ b/tests/settings/test_validator.py @@ -5,52 +5,52 @@ from unittest import mock from unittest.mock import patch from lodel.exceptions import * -from lodel.settings.validator import * +from lodel.validator.validator import * -class SettingValidatorTestCase(unittest.TestCase): +class ValidatorTestCase(unittest.TestCase): def test_init_basic(self): """ Testing the SettingsValidator class instanciation""" - valid = SettingValidator('string') + valid = Validator('string') #trying to call it valid('test') def test_init_badname(self): - """ Testing SettingValidator instanciation with non existing validator + """ Testing Validator instanciation with non existing validator name""" with self.assertRaises(LodelFatalError): - SettingValidator('qklfhsdufgsdyfugigsdfsdlcknsdp') + Validator('qklfhsdufgsdyfugigsdfsdlcknsdp') def test_noneswitch(self): """ Testing the none_is_valid switch given at validator instanciation """ - none_invalid = SettingValidator('int') - none_valid = SettingValidator('int', none_is_valid = True) + none_invalid = Validator('int') + none_valid = Validator('int', none_is_valid = True) none_valid(None) - with self.assertRaises(SettingsValidationError): + with self.assertRaises(ValidationError): none_invalid(None) def test_validator_registration(self): - """ Testing the register_validator method of SettingValidator """ + """ Testing the register_validator method of Validator """ mockfun = mock.MagicMock() vname = 'lfkjdshfkuhsdygsuuyfsduyf' testval = 'foo' - SettingValidator.register_validator(vname, mockfun, 'test validator') + Validator.register_validator(vname, mockfun, 'test validator') #Using registered validator - valid = SettingValidator(vname) + valid = Validator(vname) valid(testval) mockfun.assert_called_once_with(testval) def test_validator_optargs_forwarding(self): - """ Testing the ability for SettingValidator to forward optional + """ Testing the ability for Validator to forward optional arguments """ mockfun = mock.MagicMock() vname = 'lkjdsfhsdiufhisduguig' testval = 'azertyuiop' - SettingValidator.register_validator(vname, mockfun, 'test validator') + Validator.register_validator(vname, mockfun, 'test validator') #Using registered validator with more arguments - valid = SettingValidator(vname, + valid = Validator(vname, arga = 'a', argb = 42, argc = '1337') valid(testval) mockfun.assert_called_once_with(