add custom validator

This commit is contained in:
gwen 2012-11-19 09:51:40 +01:00
parent b353c6ba60
commit 5969eaa2d6
2 changed files with 39 additions and 19 deletions

View file

@ -40,6 +40,8 @@ class Config(object):
#mandatory means: a mandatory option has to have a value that is not None
_cfgimpl_mandatory = True
_cfgimpl_frozen = True
#enables validation function for options if set
_cfgimpl_validator = False
_cfgimpl_owner = default_owner
_cfgimpl_toplevel = None
@ -248,9 +250,9 @@ class Config(object):
return value
else:
return value
rootconfig = self._cfgimpl_get_toplevel()
try:
result = opt_or_descr.getcallback_value(
self._cfgimpl_get_toplevel())
result = opt_or_descr.getcallback_value(rootconfig)
except NoValueReturned, err:
pass
else:
@ -264,7 +266,8 @@ class Config(object):
raise ConfigError('invalid calculated value returned'
' for option {0} : shall not be a list'.format(name))
_result = result
if _result != None and not opt_or_descr.validate(_result):
if _result != None and not opt_or_descr.validate(_result,
rootconfig._cfgimpl_validator):
raise ConfigError('invalid calculated value returned'
' for option {0}'.format(name))
self._cfgimpl_values[name] = _result
@ -455,6 +458,7 @@ class Config(object):
rootconfig.cfgimpl_disable_property('hidden')
rootconfig.cfgimpl_enable_property('disabled')
rootconfig._cfgimpl_mandatory = True
rootconfig._cfgimpl_validator = True
def cfgimpl_read_write(self):
"convenience method to freeze, hidde and disable"

View file

@ -20,6 +20,7 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
# ____________________________________________________________
from types import FunctionType
from tiramisu.basetype import HiddenBaseType, DisabledBaseType
from tiramisu.error import (ConfigError, ConflictConfigError, NotFoundError,
RequiresError, RequirementRecursionError, MandatoryError,
@ -92,7 +93,7 @@ class Option(HiddenBaseType, DisabledBaseType):
_force_default_on_freeze = False
def __init__(self, name, doc, default=None, default_multi=None,
requires=None, mandatory=False, multi=False, callback=None,
callback_params=None):
callback_params=None, validator=None, validator_args={}):
"""
:param default: ['bla', 'bla', 'bla']
:param default_multi: 'bla' (used in case of a reset to default only at
@ -103,6 +104,14 @@ class Option(HiddenBaseType, DisabledBaseType):
self._requires = requires
self._mandatory = mandatory
self.multi = multi
self._validator = None
self._validator_args = None
if validator is not None:
if type(validator) != FunctionType:
raise TypeError("validator must be a function")
self._validator = validator
if validator_args is not None:
self._validator_args = validator_args
if not self.multi and default_multi is not None:
raise ConfigError("a default_multi is set whereas multi is False"
" in option: {0}".format(name))
@ -123,17 +132,29 @@ class Option(HiddenBaseType, DisabledBaseType):
if self.multi == True:
if default == None:
default = []
if not isinstance(default, list) or not self.validate(default):
if not isinstance(default, list):
raise ConfigError("invalid default value {0} "
"for option {1} : not list type".format(str(default), name))
if not self.validate(default, False):
raise ConfigError("invalid default value {0} "
"for option {1}".format(str(default), name))
else:
if default != None and not self.validate(default):
if default != None and not self.validate(default, False):
raise ConfigError("invalid default value {0} "
"for option {1}".format(str(default), name))
self.default = default
self.properties = [] # 'hidden', 'disabled'...
def validate(self, value):
def validate(self, value, validate=True):
"""
:param value: the option's value
:param validate: if true enables ``self._validator`` validation
"""
# customizing the validator
if validate and value is not None and self._validator is not None:
if not self._validator(value, **self._validator_args):
return False
# generic calculation
if self.multi == False:
# None allows the reset of the value
if value != None:
@ -235,7 +256,8 @@ class Option(HiddenBaseType, DisabledBaseType):
:param who : is **not necessarily** a owner because it cannot be a list
:type who: string """
name = self._name
if not self.validate(value):
rootconfig = config._cfgimpl_get_toplevel()
if not self.validate(value, rootconfig._cfgimpl_validator):
raise ConfigError('invalid value %s for option %s' % (value, name))
if self.is_mandatory():
# value shall not be '' for a mandatory option
@ -253,7 +275,7 @@ class Option(HiddenBaseType, DisabledBaseType):
if config.is_frozen() and self.is_frozen():
raise TypeError('cannot change the value to %s for '
'option %s' % (str(value), name))
'option %s this option is frozen' % (str(value), name))
apply_requires(self, config)
if type(config._cfgimpl_values[name]) == Multi:
config._cfgimpl_previous_values[name] = list(config._cfgimpl_values[name])
@ -283,7 +305,8 @@ class ChoiceOption(Option):
def __init__(self, name, doc, values, default=None, default_multi=None,
requires=None, mandatory=False, multi=False, callback=None,
callback_params=None, open_values=False):
callback_params=None, open_values=False, validator=None,
validator_args={}):
self.values = values
if open_values not in [True, False]:
raise ConfigError('Open_values must be a boolean for '
@ -292,7 +315,8 @@ class ChoiceOption(Option):
super(ChoiceOption, self).__init__(name, doc, default=default,
default_multi=default_multi, callback=callback,
callback_params=callback_params, requires=requires,
multi=multi, mandatory=mandatory)
multi=multi, mandatory=mandatory, validator=validator,
validator_args=validator_args)
def _validate(self, value):
if not self.open_values:
@ -306,14 +330,6 @@ class BoolOption(Option):
def _validate(self, value):
return isinstance(value, bool)
# config level validator
# def setoption(self, config, value, who):
# name = self._name
# if value and self._validator is not None:
# toplevel = config._cfgimpl_get_toplevel()
# self._validator(toplevel)
# super(BoolOption, self).setoption(config, value, who)
class IntOption(Option):
opt_type = 'int'