add masters/slaves in the Values()

This commit is contained in:
gwen 2013-02-22 11:09:17 +01:00
parent e6d5d349c8
commit 8f4efe6b00
3 changed files with 77 additions and 44 deletions

View File

@ -27,7 +27,8 @@ from tiramisu.error import (PropertiesOptionError, ConfigError, NotFoundError,
from tiramisu.option import (OptionDescription, Option, SymLinkOption, from tiramisu.option import (OptionDescription, Option, SymLinkOption,
apply_requires) apply_requires)
from tiramisu.setting import groups, owners, Setting from tiramisu.setting import groups, owners, Setting
from tiramisu.value import OptionValues from tiramisu.value import Values
# ____________________________________________________________ # ____________________________________________________________
class Config(object): class Config(object):
@ -53,9 +54,9 @@ class Config(object):
self._cfgimpl_context = self self._cfgimpl_context = self
else: else:
self._cfgimpl_context = context self._cfgimpl_context = context
if parent == None: if parent is None:
self._cfgimpl_settings = Setting() self._cfgimpl_settings = Setting()
self._cfgimpl_values = OptionValues(self._cfgimpl_context) self._cfgimpl_values = Values(self._cfgimpl_context)
else: else:
if context is None: if context is None:
raise ConfigError("cannot find a value for this config") raise ConfigError("cannot find a value for this config")
@ -95,7 +96,7 @@ class Config(object):
if self._cfgimpl_descr.group_type == groups.master: if self._cfgimpl_descr.group_type == groups.master:
mastername = self._cfgimpl_descr._name mastername = self._cfgimpl_descr._name
masteropt = getattr(self._cfgimpl_descr, mastername) masteropt = getattr(self._cfgimpl_descr, mastername)
self._cfgimpl_values.master_groups[masteropt] = [] self._cfgimpl_values.masters[masteropt] = []
for child in self._cfgimpl_descr._children: for child in self._cfgimpl_descr._children:
if isinstance(child, OptionDescription): if isinstance(child, OptionDescription):
@ -104,11 +105,9 @@ class Config(object):
context=self._cfgimpl_context) context=self._cfgimpl_context)
if (self._cfgimpl_descr.group_type == groups.master and if (self._cfgimpl_descr.group_type == groups.master and
child != masteropt): child != masteropt):
self._cfgimpl_values.master_groups[child] = [] self._cfgimpl_values.slaves[child] = masteropt
self._cfgimpl_values.master_groups[masteropt].append(child) self._cfgimpl_values.masters[masteropt].append(child)
if self._cfgimpl_descr.group_type == groups.master:
print self._cfgimpl_values.master_groups
# ____________________________________________________________ # ____________________________________________________________
# attribute methods # attribute methods
def __setattr__(self, name, value): def __setattr__(self, name, value):
@ -379,7 +378,6 @@ class Config(object):
__repr__ = __str__ __repr__ = __str__
def getpaths(self, include_groups=False, allpaths=False, mandatory=False): def getpaths(self, include_groups=False, allpaths=False, mandatory=False):
"""returns a list of all paths in self, recursively, taking care of """returns a list of all paths in self, recursively, taking care of
the context of properties (hidden/disabled) the context of properties (hidden/disabled)
@ -497,6 +495,7 @@ class Config(object):
""" """
return self._find(bytype, byname, byvalue, byattrs, first=True) return self._find(bytype, byname, byvalue, byattrs, first=True)
def make_dict(config, flatten=False): def make_dict(config, flatten=False):
"""export the whole config into a `dict` """export the whole config into a `dict`
:returns: dict of Option's name (or path) and values""" :returns: dict of Option's name (or path) and values"""
@ -515,6 +514,7 @@ def make_dict(config, flatten=False):
options = dict(pathsvalues) options = dict(pathsvalues)
return options return options
def mandatory_warnings(config): def mandatory_warnings(config):
"""convenience function to trace Options that are mandatory and """convenience function to trace Options that are mandatory and
where no value has been set where no value has been set

View File

@ -25,3 +25,5 @@ class NoValueReturned(Exception):
pass pass
class OptionValueError(Exception): class OptionValueError(Exception):
pass pass
class MultiTypeError(Exception):
pass

View File

@ -21,9 +21,9 @@
# the whole pypy projet is under MIT licence # the whole pypy projet is under MIT licence
# ____________________________________________________________ # ____________________________________________________________
from tiramisu.error import NoValueReturned, MandatoryError from tiramisu.error import NoValueReturned, MandatoryError
from tiramisu.setting import owners from tiramisu.setting import owners, multitypes
class OptionValues(object): class Values(object):
def __init__(self, context): def __init__(self, context):
""" """
Initializes the values's dict. Initializes the values's dict.
@ -34,17 +34,25 @@ class OptionValues(object):
"Config's root indeed is in charge of the `Option()`'s values" "Config's root indeed is in charge of the `Option()`'s values"
self.values = {} self.values = {}
self.previous_values = {} self.previous_values = {}
self.master_groups = {} self.masters = {}
self.slaves = {}
self.context = context self.context = context
def _get_value(self, opt): def _get_value(self, opt):
"special case for the multis: they never return None" "special case for the multis: they never return None"
if opt not in self.values:
if opt.is_multi(): if opt.is_multi():
if opt not in self.values: if opt in self.slaves:
# slave
multitype = multitypes.slave
elif opt in self.masters:
# master
multitype = multitypes.master
# FIXME : default value for a multi, we shall work on groups # FIXME : default value for a multi, we shall work on groups
return Multi(opt.getdefault(), self.context, opt)
else: else:
if opt not in self.values: multitype = multitypes.default
return Multi(opt.getdefault(), self.context, opt, multitype)
else:
return opt.getdefault() return opt.getdefault()
return self.values[opt] return self.values[opt]
@ -128,6 +136,21 @@ class OptionValues(object):
return value return value
def __setitem__(self, opt, value): def __setitem__(self, opt, value):
if opt in self.masters:
masterlen = len(value)
for slave in masters[opt]:
if len(self._get_value(slave)) != masterlen:
raise MultiTypeError("invalid len for the slave: {0}"
"which has {1} as master".format(slave._name,
master._name))
elif opt in self.slaves:
if len(self._get_value(self.slaves[opt])) != len(value):
raise MultiTypeError("invalid len for the slave: {0}"
"which has {1} as master".format(slave._name,
master._name))
self.setitem(opt, value)
def setitem(self, opt, value):
self.set_previous_value(opt) self.set_previous_value(opt)
self.values[opt] = value self.values[opt] = value
self.setowner(opt, self.context._cfgimpl_settings.getowner()) self.setowner(opt, self.context._cfgimpl_settings.getowner())
@ -149,7 +172,7 @@ class OptionValues(object):
class Multi(list): class Multi(list):
"""multi options values container """multi options values container
that support item notation for the values of multi options""" that support item notation for the values of multi options"""
def __init__(self, lst, context, opt, multitype=settings.multitypes.default): def __init__(self, lst, context, opt, multitype):
""" """
:param lst: the Multi wraps a list value :param lst: the Multi wraps a list value
:param context: the home config that has the settings and the values :param context: the home config that has the settings and the values
@ -160,40 +183,48 @@ class Multi(list):
self.values = context._cfgimpl_values self.values = context._cfgimpl_values
self.multitype = multitype self.multitype = multitype
super(Multi, self).__init__(lst) super(Multi, self).__init__(lst)
if multitype == multitypes.master:
self.slaves = context._cfgimpl_values.masters[opt]
else:
self.slaves = None
def __setitem__(self, key, value): def __setitem__(self, key, value):
self._setvalue(value, key, who=self.settings.getowner()) self._validate(value)
self.values[self.opt] = self
super(Multi, self).__setitem__(key, value)
def append(self, value): def append(self, value, force=False):
"""the list value can be updated (appened) """the list value can be updated (appened)
only if the option is a master only if the option is a master
""" """
self._setvalue(value, who=self.settings.getowner(self.opt)) if not force:
if self.multitype == multitypes.slave:
raise MultiTypeError("cannot append a value on a multi option {0}"
" wich is a slave".format(self.opt._name))
elif self.multitype == multitypes.master:
for slave in self.slaves:
self.values[slave].append(None, force=True)
self._validate(value)
self.values.setitem(self.opt, self)
super(Multi, self).append(value)
def _setvalue(self, value, key=None, who=None): def _validate(self, value):
if value != None: if value != None and not self.opt._validate(value):
if not self.opt._validate(value):
raise ConfigError("invalid value {0} " raise ConfigError("invalid value {0} "
"for option {1}".format(str(value), self.opt._name)) "for option {1}".format(str(value), self.opt._name))
oldvalue = list(self)
if key is None:
super(Multi, self).append(value)
else:
super(Multi, self).__setitem__(key, value)
if who != None:
if not isinstance(who, owners.Owner):
raise TypeError("invalid owner {0} for the value {1}".format(
str(who), str(value)))
self.values.setowner(self.opt, getattr(owners, who))
self.values.previous_values[self.opt] = oldvalue
def pop(self, key): def pop(self, key, force=False):
"""the list value can be updated (poped) """the list value can be updated (poped)
only if the option is a master only if the option is a master
:param key: index of the element to pop :param key: index of the element to pop
:return: the requested element :return: the requested element
""" """
self.values.setowner(opt, self.settings.get_owner()) if not force:
self.values.previous_values[self.opt] = list(self) if self.multitype == multitypes.slave:
raise MultiTypeError("cannot append a value on a multi option {0}"
" wich is a slave".format(self.opt._name))
elif self.multitype == multitypes.master:
for slave in self.slaves:
self.values[slave].pop(key, force=True)
self.values.setitem(self.opt, self)
return super(Multi, self).pop(key) return super(Multi, self).pop(key)