From 9c2dcc164c886174f615682a5dd45a005f5967d0 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Sat, 13 Apr 2013 22:50:55 +0200 Subject: [PATCH] attribute in Option now starts with '_' add ValidateError add consistancies in Option remove byattr in find --- test/test_config_api.py | 6 +- test/test_option_setting.py | 8 +- tiramisu/config.py | 60 ++++----- tiramisu/error.py | 26 ++++ tiramisu/option.py | 254 +++++++++++++++++++++++++++--------- tiramisu/value.py | 47 +++---- 6 files changed, 281 insertions(+), 120 deletions(-) diff --git a/test/test_config_api.py b/test/test_config_api.py index 26589e4..538cd8b 100644 --- a/test/test_config_api.py +++ b/test/test_config_api.py @@ -160,9 +160,9 @@ def test_find_in_config(): assert conf.find_first(bytype=BoolOption, byname='dummy') == conf.unwrap_from_path('gc.dummy') assert conf.find(byvalue=False, byname='dummy') == [conf.unwrap_from_path('gc.dummy')] assert conf.find_first(byvalue=False, byname='dummy') == conf.unwrap_from_path('gc.dummy') - # byattrs - assert conf.find_first(byattrs= dict(default=2.3)) == conf.unwrap_from_path('gc.float') - assert conf.find_first(byvalue=False, byname='dummy', byattrs=dict(default=False)) == conf.unwrap_from_path('gc.dummy') + ## byattrs + #assert conf.find_first(byattrs= dict(default=2.3)) == conf.unwrap_from_path('gc.float') + #assert conf.find_first(byvalue=False, byname='dummy', byattrs=dict(default=False)) == conf.unwrap_from_path('gc.dummy') def test_does_not_find_in_config(): descr = make_description() diff --git a/test/test_option_setting.py b/test/test_option_setting.py index e0af336..7beaf91 100644 --- a/test/test_option_setting.py +++ b/test/test_option_setting.py @@ -69,7 +69,7 @@ def test_reset_with_multi(): config.unwrap_from_path("string").reset(config) # assert config.string == ["string"] assert config.cfgimpl_get_values().getowner(s) == 'default' - raises(ConfigError, "config.string = None") + raises(ValidateError, "config.string = None") def test_default_with_multi(): "default with multi is a list" @@ -230,7 +230,7 @@ def test_multi_with_bool(): s = BoolOption("bool", "", default=[False], multi=True) descr = OptionDescription("options", "", [s]) config = Config(descr) - assert descr.bool.multi == True + assert descr.bool.is_multi() == True config.bool = [True, False] assert config.cfgimpl_get_values()[s] == [True, False] assert config.bool == [True, False] @@ -239,8 +239,8 @@ def test_multi_with_bool_two(): s = BoolOption("bool", "", default=[False], multi=True) descr = OptionDescription("options", "", [s]) config = Config(descr) - assert descr.bool.multi == True - raises(ConfigError, "config.bool = True") + assert descr.bool.is_multi() == True + raises(ValidateError, "config.bool = True") def test_choice_access_with_multi(): ch = ChoiceOption("t1", "", ("a", "b"), default=["a"], multi=True) diff --git a/tiramisu/config.py b/tiramisu/config.py index dfc3560..811f931 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -54,6 +54,9 @@ class SubConfig(object): def cfgimpl_get_values(self): return self._cfgimpl_context._cfgimpl_values + def cfgimpl_get_consistancies(self): + return self.cfgimpl_get_context().cfgimpl_get_description()._consistancies + def cfgimpl_get_description(self): return self._cfgimpl_descr @@ -101,7 +104,8 @@ class SubConfig(object): def __getattr__(self, name): return self._getattr(name) - def _getattr(self, name, force_permissive=False, force_properties=None): + def _getattr(self, name, force_permissive=False, force_properties=None, + validate=True): """ attribute notation mechanism for accessing the value of an option :param name: attribute name @@ -115,13 +119,14 @@ class SubConfig(object): force_permissive=force_permissive, force_properties=force_properties) return homeconfig._getattr(name, force_permissive=force_permissive, - force_properties=force_properties) + force_properties=force_properties, + validate=validate) opt_or_descr = getattr(self._cfgimpl_descr, name) # symlink options if type(opt_or_descr) == SymLinkOption: rootconfig = self.cfgimpl_get_context() path = rootconfig.cfgimpl_get_description().get_path_by_opt(opt_or_descr.opt) - return getattr(rootconfig, path) + return rootconfig._getattr(path, validate=validate) self._validate(name, opt_or_descr, force_permissive=force_permissive) if isinstance(opt_or_descr, OptionDescription): children = self.cfgimpl_get_description()._children @@ -136,7 +141,8 @@ class SubConfig(object): # if it were in __dict__ it would have been found already object.__getattr__(self, name) return self.cfgimpl_get_values()._getitem(opt_or_descr, - force_properties=force_properties) + force_properties=force_properties, + validate=validate) def setoption(self, name, child, value): """effectively modifies the value of an Option() @@ -279,35 +285,31 @@ class SubConfig(object): context_descr = self.cfgimpl_get_context().cfgimpl_get_description() return context_descr.get_path_by_opt(descr) - def find(self, bytype=None, byname=None, byvalue=None, byattrs=None, - type_='option'): + def find(self, bytype=None, byname=None, byvalue=None, type_='option'): """ finds a list of options recursively in the config :param bytype: Option class (BoolOption, StrOption, ...) :param byname: filter by Option._name :param byvalue: filter by the option's value - :param byattrs: dict of option attributes (default, callback...) :returns: list of matching Option objects """ return self.cfgimpl_get_context()._find(bytype, byname, byvalue, - byattrs, first=False, + first=False, type_=type_, _subpath=self.getpath()) - def find_first(self, bytype=None, byname=None, byvalue=None, byattrs=None, - type_='option'): + def find_first(self, bytype=None, byname=None, byvalue=None, type_='option'): """ finds an option recursively in the config :param bytype: Option class (BoolOption, StrOption, ...) :param byname: filter by Option._name :param byvalue: filter by the option's value - :param byattrs: dict of option attributes (default, callback...) :returns: list of matching Option objects """ return self.cfgimpl_get_context()._find(bytype, byname, byvalue, - byattrs, first=True, + first=True, type_=type_, _subpath=self.getpath()) @@ -324,7 +326,6 @@ class SubConfig(object): for path in self.cfgimpl_get_context()._find(bytype=Option, byname=withoption, byvalue=withvalue, - byattrs=None, first=False, type_='path', _subpath=mypath): @@ -436,7 +437,7 @@ class Config(SubConfig): def getpath(self): return None - def _find(self, bytype, byname, byvalue, byattrs, first, type_='option', + def _find(self, bytype, byname, byvalue, first, type_='option', _subpath=None): """ convenience method for finding an option that lives only in the subtree @@ -470,18 +471,17 @@ class Config(SubConfig): return True return False - def _filter_by_attrs(): - if byattrs is None: - return True - for key, value in byattrs.items(): - if not hasattr(option, key): - return False - else: - if getattr(option, key) != value: - return False - else: - continue - return True + #def _filter_by_attrs(): + # if byattrs is None: + # return True + # for key, val in byattrs.items(): + # print "----", path, key + # if path == key or path.endswith('.' + key): + # if value == val: + # return True + # else: + # return False + # return False if type_ not in ('option', 'path', 'value'): raise ValueError('unknown type_ type {} for _find'.format(type_)) find_results = [] @@ -497,15 +497,15 @@ class Config(SubConfig): continue if not _filter_by_value(): continue - if not _filter_by_type(): - continue - if not _filter_by_attrs(): - continue #remove option with propertyerror, ... try: value = getattr(self, path) except: # a property restricts the access of the value continue + if not _filter_by_type(): + continue + #if not _filter_by_attrs(): + # continue if type_ == 'value': retval = value elif type_ == 'path': diff --git a/tiramisu/error.py b/tiramisu/error.py index 3d82c65..4d5c6ab 100644 --- a/tiramisu/error.py +++ b/tiramisu/error.py @@ -1,27 +1,53 @@ +class ValidateError(Exception): + "If validation failed" + pass + + class AmbigousOptionError(Exception): pass + + class NoMatchingOptionFound(AttributeError): pass + + class ConfigError(Exception): pass + + class ConflictConfigError(ConfigError): pass + + class PropertiesOptionError(AttributeError): def __init__(self, msg, proptype): self.proptype = proptype super(PropertiesOptionError, self).__init__(msg) + class NotFoundError(Exception): pass + + class MethodCallError(Exception): pass + + class RequiresError(Exception): pass + + class RequirementRecursionError(RequiresError): pass + + class MandatoryError(Exception): pass + + class OptionValueError(Exception): pass + + class MultiTypeError(Exception): pass diff --git a/tiramisu/option.py b/tiramisu/option.py index befeec7..7a49b98 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -23,8 +23,10 @@ import re from copy import copy from types import FunctionType +from IPy import IP + from tiramisu.error import (ConfigError, NotFoundError, ConflictConfigError, - RequiresError) + RequiresError, ValidateError) from tiramisu.setting import groups, multitypes name_regexp = re.compile(r'^\d+') @@ -44,7 +46,7 @@ def valid_name(name): class BaseInformation(object): - __slots__ = ('informations') + __slots__ = ('_informations') def set_information(self, key, value): """updates the information's attribute @@ -53,15 +55,15 @@ class BaseInformation(object): :param key: information's key (ex: "help", "doc" :param value: information's value (ex: "the help string") """ - self.informations[key] = value + self._informations[key] = value def get_information(self, key, default=None): """retrieves one information's item :param key: the item string (ex: "help") """ - if key in self.informations: - return self.informations[key] + if key in self._informations: + return self._informations[key] elif default is not None: return default else: @@ -74,9 +76,9 @@ class Option(BaseInformation): Reminder: an Option object is **not** a container for the value """ - __slots__ = ('_name', '_requires', 'multi', '_validator', 'default_multi', - 'default', '_properties', 'callback', 'multitype', - 'master_slaves') + __slots__ = ('_name', '_requires', '_multi', '_validator', '_default_multi', + '_default', '_properties', '_callback', '_multitype', + '_master_slaves', '_consistency') def __init__(self, name, doc, default=None, default_multi=None, requires=None, multi=False, callback=None, @@ -103,11 +105,12 @@ class Option(BaseInformation): if not valid_name(name): raise NameError("invalid name: {0} for option".format(name)) self._name = name - self.informations = {} + self._informations = {} self.set_information('doc', doc) validate_requires_arg(requires, self._name) self._requires = requires - self.multi = multi + self._multi = multi + self._consistency = None if validator is not None: if type(validator) != FunctionType: raise TypeError("validator must be a function") @@ -116,7 +119,7 @@ class Option(BaseInformation): self._validator = (validator, validator_args) else: self._validator = None - 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" " in option: {0}".format(name)) if default_multi is not None and not self._validate(default_multi): @@ -129,27 +132,27 @@ class Option(BaseInformation): raise ConfigError("params defined for a callback function but " "no callback defined yet for option {0}".format(name)) if callback is not None: - self.callback = (callback, callback_params) + self._callback = (callback, callback_params) else: - self.callback = None - if self.multi: + self._callback = None + if self._multi: if default is None: default = [] - if not isinstance(default, list): - raise ConfigError("invalid default value {0} " - "for option {1} : not list type" - "".format(str(default), name)) + #if not isinstance(default, list): + # raise ValidateError("invalid default value {0} " + # "for option {1} : not list type" + # "".format(str(default), name)) if not self.validate(default): - raise ConfigError("invalid default value {0} " - "for option {1}" - "".format(str(default), name)) - self.multitype = multitypes.default - self.default_multi = default_multi + raise ValidateError("invalid default value {0} " + "for option {1}" + "".format(str(default), name)) + self._multitype = multitypes.default + self._default_multi = default_multi else: if default is not None and not self.validate(default): - raise ConfigError("invalid default value {0} " - "for option {1}".format(str(default), name)) - self.default = default + raise ValidateError("invalid default value {0} " + "for option {1}".format(str(default), name)) + self._default = default if properties is None: properties = () if not isinstance(properties, tuple): @@ -157,26 +160,34 @@ class Option(BaseInformation): ' must be a tuple'.format(type(properties), self._name)) self._properties = properties # 'hidden', 'disabled'... - def validate(self, value, validate=True): + def validate(self, value, context=None, validate=True): """ :param value: the option's value :param validate: if true enables ``self._validator`` validation """ # generic calculation - if not self.multi: + if context is not None: + cons = context.cfgimpl_get_description() + else: + cons = None + if not self._multi: # None allows the reset of the value if value is not None: # customizing the validator if validate and self._validator is not None and \ not self._validator[0](value, **self._validator[1]): return False - return self._validate(value) + if not self._validate(value): + return False + if cons is not None: + return cons.valid_consistency(self, value, context, None) else: if not isinstance(value, list): - raise ConfigError("invalid value {0} " - "for option {1} which must be a list" - "".format(value, self._name)) - for val in value: + raise ValidateError("invalid value {0} " + "for option {1} which must be a list" + "".format(value, self._name)) + for index in range(0, len(value)): + val = value[index] # None allows the reset of the value if val is not None: # customizing the validator @@ -185,23 +196,31 @@ class Option(BaseInformation): return False if not self._validate(val): return False + if cons is not None and not cons.valid_consistency(self, val, context, index): + return False return True def getdefault(self, default_multi=False): "accessing the default value" if not default_multi or not self.is_multi(): - return self.default + return self._default else: return self.getdefault_multi() def getdefault_multi(self): "accessing the default value for a multi" - return self.default_multi + return self._default_multi + + def get_multitype(self): + return self._multitype + + def get_master_slaves(self): + return self._master_slaves def is_empty_by_default(self): "no default value has been set yet" - if ((not self.is_multi() and self.default is None) or - (self.is_multi() and (self.default == [] or None in self.default))): + if ((not self.is_multi() and self._default is None) or + (self.is_multi() and (self._default == [] or None in self._default))): return True return False @@ -211,7 +230,7 @@ class Option(BaseInformation): def has_callback(self): "to know if a callback has been defined or not" - if self.callback is None: + if self._callback is None: return False else: return True @@ -225,11 +244,23 @@ class Option(BaseInformation): return value def is_multi(self): - return self.multi + return self._multi + + def cons_not_equal(self, opt, value, context, index, opts): + values = [value] + descr = context.cfgimpl_get_description() + for opt_ in opts: + if opt_ is not opt: + path = descr.get_path_by_opt(opt_) + val = context._getattr(path, validate=False) + if val in values: + return False + values.append(val) + return True class ChoiceOption(Option): - __slots__ = ('values', 'open_values', 'opt_type') + __slots__ = ('_values', '_open_values', 'opt_type') opt_type = 'string' def __init__(self, name, doc, values, default=None, default_multi=None, @@ -238,11 +269,11 @@ class ChoiceOption(Option): validator_args=None, properties=()): if not isinstance(values, tuple): raise ConfigError('values must be a tuple for {0}'.format(name)) - self.values = values + self._values = values if open_values not in (True, False): raise ConfigError('Open_values must be a boolean for ' '{0}'.format(name)) - self.open_values = open_values + self._open_values = open_values super(ChoiceOption, self).__init__(name, doc, default=default, default_multi=default_multi, callback=callback, @@ -254,8 +285,8 @@ class ChoiceOption(Option): properties=properties) def _validate(self, value): - if not self.open_values: - return value is None or value in self.values + if not self._open_values: + return value is None or value in self._values else: return True @@ -301,8 +332,9 @@ class UnicodeOption(Option): class SymLinkOption(object): - __slots__ = ('_name', 'opt') + __slots__ = ('_name', 'opt', '_consistency') opt_type = 'symlink' + _consistency = None def __init__(self, name, path, opt): self._name = name @@ -320,27 +352,112 @@ class SymLinkOption(object): class IPOption(Option): - __slots__ = ('opt_type') + __slots__ = ('opt_type', '_only_private') opt_type = 'ip' + def set_private(self): + self._only_private = True + def _validate(self, value): - # by now the validation is nothing but a string, use IPy instead - return isinstance(value, str) + try: + only_private = self._only_private + except AttributeError: + only_private = False + try: + ip = IP('{0}/32'.format(value)) + if only_private: + return ip.iptype() == 'PRIVATE' + return True + except ValueError: + return False + + +class NetworkOption(Option): + __slots__ = ('opt_type') + opt_type = 'network' + + def _validate(self, value): + try: + IP(value) + return True + except ValueError: + return False class NetmaskOption(Option): __slots__ = ('opt_type') opt_type = 'netmask' + def __init__(self, name, doc, default=None, default_multi=None, + requires=None, multi=False, callback=None, + callback_params=None, validator=None, validator_args=None, + properties=None, opt_ip=None): + if opt_ip is not None and not isinstance(opt_ip, IPOption) and \ + not isinstance(opt_ip, NetworkOption): + raise ValueError('opt_ip must be a IPOption not {}'.format(type(opt_ip))) + super(NetmaskOption, self).__init__(name, doc, default=default, + default_multi=default_multi, + callback=callback, + callback_params=callback_params, + requires=requires, + multi=multi, + validator=validator, + validator_args=validator_args, + properties=properties) + if opt_ip is None: + pass + elif isinstance(opt_ip, IPOption): + self._consistency = ('cons_ip_netmask', (self, opt_ip)) + elif isinstance(opt_ip, NetworkOption): + self._consistency = ('cons_network_netmask', (self, opt_ip)) + else: + raise ValueError('unknown type for opt_ip') + def _validate(self, value): - # by now the validation is nothing but a string, use IPy instead - return isinstance(value, str) + try: + IP('0.0.0.0/{}'.format(value)) + return True + except ValueError: + return False + + def cons_network_netmask(self, opt, value, context, index, opts): + #opts must be (netmask, network) options + return self._cons_netmask(opt, value, context, index, opts, False) + + def cons_ip_netmask(self, opt, value, context, index, opts): + #opts must be (netmask, ip) options + return self._cons_netmask(opt, value, context, index, opts, True) + + def _cons_netmask(self, opt, value, context, index, opts, make_net): + opt_netmask, opt_ipnetwork = opts + descr = context.cfgimpl_get_description() + if opt is opt_ipnetwork: + val_ipnetwork = value + path = descr.get_path_by_opt(opt_netmask) + val_netmask = context._getattr(path, validate=False) + if opt_netmask.is_multi(): + val_netmask = val_netmask[index] + if val_netmask is None: + return True + else: + val_netmask = value + path = descr.get_path_by_opt(opt_ipnetwork) + val_ipnetwork = getattr(context, path) + if opt_ipnetwork.is_multi(): + val_ipnetwork = val_ipnetwork[index] + if val_ipnetwork is None: + return True + try: + IP('{}/{}'.format(val_ipnetwork, val_netmask, make_net=make_net)) + return True + except ValueError: + return False class OptionDescription(BaseInformation): """Config's schema (organisation, group) and container of Options""" __slots__ = ('_name', '_requires', '_cache_paths', '_group_type', - '_properties', '_children') + '_properties', '_children', '_consistencies') def __init__(self, name, doc, children, requires=None, properties=()): """ @@ -350,7 +467,7 @@ class OptionDescription(BaseInformation): if not valid_name(name): raise NameError("invalid name: {0} for option descr".format(name)) self._name = name - self.informations = {} + self._informations = {} self.set_information('doc', doc) child_names = [child._name for child in children] #better performance like this @@ -366,6 +483,7 @@ class OptionDescription(BaseInformation): validate_requires_arg(requires, self._name) self._requires = requires self._cache_paths = None + self._consistencies = None if not isinstance(properties, tuple): raise ConfigError('invalid properties type {0} for {1},' ' must be a tuple'.format(type(properties), self._name)) @@ -409,12 +527,13 @@ class OptionDescription(BaseInformation): def getchildren(self): return self._children[1] - def build_cache(self, cache_path=None, cache_option=None, _currpath=None): + def build_cache(self, cache_path=None, cache_option=None, _currpath=None, _consistencies=None): if _currpath is None and self._cache_paths is not None: return if _currpath is None: save = True _currpath = [] + _consistencies = {} else: save = False if cache_path is None: @@ -426,9 +545,16 @@ class OptionDescription(BaseInformation): continue cache_option.append(option) cache_path.append(str('.'.join(_currpath + [attr]))) - if isinstance(option, OptionDescription): + if not isinstance(option, OptionDescription): + if option._consistency is not None: + func, opts = option._consistency + for opt in opts: + if opt in _consistencies: + raise ValueError('opt {} already in consistency'.format(opt._name)) + _consistencies[opt] = (func, opts) + else: _currpath.append(attr) - option.build_cache(cache_path, cache_option, _currpath) + option.build_cache(cache_path, cache_option, _currpath, _consistencies) _currpath.pop() if save: #valid no duplicated option @@ -441,6 +567,7 @@ class OptionDescription(BaseInformation): '{0}'.format(child)) old = child self._cache_paths = (tuple(cache_option), tuple(cache_path)) + self._consistencies = _consistencies def get_opt_by_path(self, path): try: @@ -476,24 +603,24 @@ class OptionDescription(BaseInformation): if isinstance(child, OptionDescription): raise ConfigError("master group {} shall not have " "a subgroup".format(self._name)) - if not child.multi: + if not child.is_multi(): raise ConfigError("not allowed option {0} in group {1}" ": this option is not a multi" "".format(child._name, self._name)) if child._name == self._name: identical_master_child_name = True - child.multitype = multitypes.master + child._multitype = multitypes.master master = child else: slaves.append(child) if master is None: raise ConfigError('master group with wrong master name for {}' ''.format(self._name)) - master.master_slaves = tuple(slaves) + master._master_slaves = tuple(slaves) for child in self._children[1]: if child != master: - child.master_slaves = master - child.multitype = multitypes.slave + child._master_slaves = master + child._multitype = multitypes.slave if not identical_master_child_name: raise ConfigError("the master group: {} has not any " "master child".format(self._name)) @@ -503,6 +630,13 @@ class OptionDescription(BaseInformation): def get_group_type(self): return self._group_type + def valid_consistency(self, opt, value, context, index): + cons = self._consistencies.get(opt) + if cons is not None: + func, opts = cons + return getattr(opts[0], func)(opt, value, context, index, opts) + return True + def validate_requires_arg(requires, name): "check malformed requirements" diff --git a/tiramisu/value.py b/tiramisu/value.py index 1a7e9e2..528185a 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -18,7 +18,7 @@ # # ____________________________________________________________ from tiramisu.error import MandatoryError, MultiTypeError, \ - ConfigError # , OptionValueError + ConfigError, ValidateError from tiramisu.setting import owners, multitypes from tiramisu.autolib import carry_out_calculation @@ -44,8 +44,8 @@ class Values(object): if opt.is_multi(): value = Multi(value, self.context, opt) #if slave, had values until master's one - if opt.multitype == multitypes.slave: - masterpath = self.context.cfgimpl_get_description().get_path_by_opt(opt.master_slaves) + if opt.get_multitype() == multitypes.slave: + masterpath = self.context.cfgimpl_get_description().get_path_by_opt(opt.get_master_slaves()) mastervalue = getattr(self.context, masterpath) masterlen = len(mastervalue) if len(value) > masterlen: @@ -118,7 +118,7 @@ class Values(object): def __getitem__(self, opt): return self._getitem(opt) - def _getitem(self, opt, force_properties=None): + def _getitem(self, opt, force_properties=None, validate=True): # options with callbacks value = self._get_value(opt) setting = self.context.cfgimpl_get_settings() @@ -130,30 +130,31 @@ class Values(object): if not self.is_default_owner(opt) and ( not is_frozen or (is_frozen and not setting.has_property('force_default_on_freeze', opt, False))): - return value - value = self._getcallback_value(opt) - if opt.is_multi(): - value = self.fill_multi(opt, value) - if not opt.validate(value, setting.has_property('validator')): - raise ConfigError('invalid calculated value returned' - ' for option {0}: {1}'.format(opt._name, value)) - #suppress value if already set - self.reset(opt) + pass + else: + value = self._getcallback_value(opt) + if opt.is_multi(): + value = self.fill_multi(opt, value) + #suppress value if already set + self.reset(opt) # frozen and force default elif is_frozen and setting.has_property('force_default_on_freeze', opt, False): value = opt.getdefault() if opt.is_multi(): value = self.fill_multi(opt, value) self._test_mandatory(opt, value, force_properties) + if validate and not opt.validate(value, self.context, setting.has_property('validator')): + raise ValidateError('invalid calculated value returned' + ' for option {0}: {1}'.format(opt._name, value)) return value def __setitem__(self, opt, value): - if not opt.validate(value, - self.context.cfgimpl_get_settings().has_property('validator')): - raise ConfigError('invalid value {}' - ' for option {}'.format(value, opt._name)) + if not opt.validate(value, self.context, + self.context.cfgimpl_get_settings().has_property('validator')): + raise ValidateError('invalid value {}' + ' for option {}'.format(value, opt._name)) if opt.is_multi(): - if opt.multitype == multitypes.master: + if opt.get_multitype() == multitypes.master: masterlen = len(value) for slave in opt.master_slaves: value_slave = self._get_value(slave) @@ -165,7 +166,7 @@ class Values(object): for num in range(0, masterlen - len(value_slave)): value_slave.append(slave.getdefault_multi(), force=True) - elif opt.multitype == multitypes.slave: + elif opt.get_multitype() == multitypes.slave: if len(self._get_value(opt.master_slaves)) != len(value): raise MultiTypeError("invalid len for the slave: {0}" " which has {1} as master".format( @@ -231,11 +232,11 @@ class Multi(list): only if the option is a master """ if not force: - if self.opt.multitype == multitypes.slave: + if self.opt.get_multitype() == multitypes.slave: raise MultiTypeError("cannot append a value on a multi option {0}" " which is a slave".format(self.opt._name)) - elif self.opt.multitype == multitypes.master: - for slave in self.opt.master_slaves: + elif self.opt.get_multitype() == multitypes.master: + for slave in self.opt.get_master_slaves(): self.context.cfgimpl_get_values()[slave].append(slave.getdefault_multi(), force=True) self._validate(value) self.context.cfgimpl_get_values().setitem(self.opt, self) @@ -259,7 +260,7 @@ class Multi(list): raise MultiTypeError("cannot append a value on a multi option {0}" " which is a slave".format(self.opt._name)) elif self.opt.multitype == multitypes.master: - for slave in self.opt.master_slaves: + for slave in self.opt.get_master_slaves(): self.context.cfgimpl_get_values()[slave].pop(key, force=True) self.context.cfgimpl_get_values().setitem(self.opt, self) return super(Multi, self).pop(key)