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 #mandatory means: a mandatory option has to have a value that is not None
_cfgimpl_mandatory = True _cfgimpl_mandatory = True
_cfgimpl_frozen = True _cfgimpl_frozen = True
#enables validation function for options if set
_cfgimpl_validator = False
_cfgimpl_owner = default_owner _cfgimpl_owner = default_owner
_cfgimpl_toplevel = None _cfgimpl_toplevel = None
@ -248,9 +250,9 @@ class Config(object):
return value return value
else: else:
return value return value
rootconfig = self._cfgimpl_get_toplevel()
try: try:
result = opt_or_descr.getcallback_value( result = opt_or_descr.getcallback_value(rootconfig)
self._cfgimpl_get_toplevel())
except NoValueReturned, err: except NoValueReturned, err:
pass pass
else: else:
@ -264,7 +266,8 @@ class Config(object):
raise ConfigError('invalid calculated value returned' raise ConfigError('invalid calculated value returned'
' for option {0} : shall not be a list'.format(name)) ' for option {0} : shall not be a list'.format(name))
_result = result _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' raise ConfigError('invalid calculated value returned'
' for option {0}'.format(name)) ' for option {0}'.format(name))
self._cfgimpl_values[name] = _result self._cfgimpl_values[name] = _result
@ -455,6 +458,7 @@ class Config(object):
rootconfig.cfgimpl_disable_property('hidden') rootconfig.cfgimpl_disable_property('hidden')
rootconfig.cfgimpl_enable_property('disabled') rootconfig.cfgimpl_enable_property('disabled')
rootconfig._cfgimpl_mandatory = True rootconfig._cfgimpl_mandatory = True
rootconfig._cfgimpl_validator = True
def cfgimpl_read_write(self): def cfgimpl_read_write(self):
"convenience method to freeze, hidde and disable" "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 rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence # the whole pypy projet is under MIT licence
# ____________________________________________________________ # ____________________________________________________________
from types import FunctionType
from tiramisu.basetype import HiddenBaseType, DisabledBaseType from tiramisu.basetype import HiddenBaseType, DisabledBaseType
from tiramisu.error import (ConfigError, ConflictConfigError, NotFoundError, from tiramisu.error import (ConfigError, ConflictConfigError, NotFoundError,
RequiresError, RequirementRecursionError, MandatoryError, RequiresError, RequirementRecursionError, MandatoryError,
@ -92,7 +93,7 @@ class Option(HiddenBaseType, DisabledBaseType):
_force_default_on_freeze = False _force_default_on_freeze = False
def __init__(self, name, doc, default=None, default_multi=None, def __init__(self, name, doc, default=None, default_multi=None,
requires=None, mandatory=False, multi=False, callback=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: ['bla', 'bla', 'bla']
:param default_multi: 'bla' (used in case of a reset to default only at :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._requires = requires
self._mandatory = mandatory self._mandatory = mandatory
self.multi = multi 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: if not self.multi and default_multi is not None:
raise ConfigError("a default_multi is set whereas multi is False" raise ConfigError("a default_multi is set whereas multi is False"
" in option: {0}".format(name)) " in option: {0}".format(name))
@ -123,17 +132,29 @@ class Option(HiddenBaseType, DisabledBaseType):
if self.multi == True: if self.multi == True:
if default == None: if default == None:
default = [] default = []
if not isinstance(default, list) or not self.validate(default): if not isinstance(default, list):
raise ConfigError("invalid default value {0} " raise ConfigError("invalid default value {0} "
"for option {1} : not list type".format(str(default), name)) "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: else:
if default != None and not self.validate(default): if default != None and not self.validate(default, False):
raise ConfigError("invalid default value {0} " raise ConfigError("invalid default value {0} "
"for option {1}".format(str(default), name)) "for option {1}".format(str(default), name))
self.default = default self.default = default
self.properties = [] # 'hidden', 'disabled'... 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: if self.multi == False:
# None allows the reset of the value # None allows the reset of the value
if value != None: if value != None:
@ -235,7 +256,8 @@ class Option(HiddenBaseType, DisabledBaseType):
:param who : is **not necessarily** a owner because it cannot be a list :param who : is **not necessarily** a owner because it cannot be a list
:type who: string """ :type who: string """
name = self._name 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)) raise ConfigError('invalid value %s for option %s' % (value, name))
if self.is_mandatory(): if self.is_mandatory():
# value shall not be '' for a mandatory option # value shall not be '' for a mandatory option
@ -253,7 +275,7 @@ class Option(HiddenBaseType, DisabledBaseType):
if config.is_frozen() and self.is_frozen(): if config.is_frozen() and self.is_frozen():
raise TypeError('cannot change the value to %s for ' 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) apply_requires(self, config)
if type(config._cfgimpl_values[name]) == Multi: if type(config._cfgimpl_values[name]) == Multi:
config._cfgimpl_previous_values[name] = list(config._cfgimpl_values[name]) 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, def __init__(self, name, doc, values, default=None, default_multi=None,
requires=None, mandatory=False, multi=False, callback=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 self.values = values
if open_values not in [True, False]: if open_values not in [True, False]:
raise ConfigError('Open_values must be a boolean for ' raise ConfigError('Open_values must be a boolean for '
@ -292,7 +315,8 @@ class ChoiceOption(Option):
super(ChoiceOption, self).__init__(name, doc, default=default, super(ChoiceOption, self).__init__(name, doc, default=default,
default_multi=default_multi, callback=callback, default_multi=default_multi, callback=callback,
callback_params=callback_params, requires=requires, callback_params=callback_params, requires=requires,
multi=multi, mandatory=mandatory) multi=multi, mandatory=mandatory, validator=validator,
validator_args=validator_args)
def _validate(self, value): def _validate(self, value):
if not self.open_values: if not self.open_values:
@ -306,14 +330,6 @@ class BoolOption(Option):
def _validate(self, value): def _validate(self, value):
return isinstance(value, bool) 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): class IntOption(Option):
opt_type = 'int' opt_type = 'int'