the value owner is a string now

This commit is contained in:
gwen 2012-11-15 10:55:14 +01:00
parent 5d23a4d921
commit eb7e393864
7 changed files with 91 additions and 183 deletions

View File

@ -40,7 +40,9 @@ def test_reset_value():
assert cfg.gc.dummy == False
cfg.gc.dummy = True
assert cfg.gc.dummy == True
cfg.gc.dummy = None
# dummy = cfg.unwrap_from_path("gc.dummy")
# dummy.reset()
# cfg.gc.dummy = False
def test_base_config_and_groups():
descr = make_description()

View File

@ -124,19 +124,19 @@ def test_make_dict():
d2 = make_dict(config, flatten=True)
assert d2 == {'a': True, 'int': 43}
def test_delattr():
"delattr, means suppression of an option in a config"
descr = OptionDescription("opt", "", [
OptionDescription("s1", "", [
BoolOption("a", "", default=False)]),
IntOption("int", "", default=42)])
c = Config(descr)
c.int = 45
assert c.int == 45
del c.int
assert c.int == 42
c.int = 45
assert c.int == 45
#def test_delattr():
# "delattr, means suppression of an option in a config"
# descr = OptionDescription("opt", "", [
# OptionDescription("s1", "", [
# BoolOption("a", "", default=False)]),
# IntOption("int", "", default=42)])
# c = Config(descr)
# c.int = 45
# assert c.int == 45
# del c.int
# assert c.int == 42
# c.int = 45
# assert c.int == 45
def test_find_in_config():
"finds option in config"

View File

@ -115,20 +115,20 @@ def test_choice_with_default():
config = Config(descr)
assert config.backend == "cli"
def test_arbitrary_option():
descr = OptionDescription("top", "", [
ArbitraryOption("a", "no help", default=None)
])
config = Config(descr)
config.a = []
config.a.append(1)
assert config.a == [1]
#def test_arbitrary_option():
# descr = OptionDescription("top", "", [
# ArbitraryOption("a", "no help", default=None)
# ])
# config = Config(descr)
# config.a = []
# config.a.append(1)
# assert config.a == [1]
descr = OptionDescription("top", "", [
ArbitraryOption("a", "no help", defaultfactory=list)
])
c1 = Config(descr)
c2 = Config(descr)
c1.a.append(1)
assert c2.a == []
assert c1.a == [1]
# descr = OptionDescription("top", "", [
# ArbitraryOption("a", "no help", defaultfactory=list)
# ])
# c1 = Config(descr)
# c2 = Config(descr)
# c1.a.append(1)
# assert c2.a == []
# assert c1.a == [1]

View File

@ -63,13 +63,13 @@ def test_reset_with_multi():
# config.string = []
config.unwrap_from_path("string").reset(config)
assert config.string == ["string"]
assert config._cfgimpl_value_owners['string'] == ['default']
assert config._cfgimpl_value_owners['string'] == 'default'
config.string = ["eggs", "spam", "foo"]
assert config._cfgimpl_value_owners['string'] == ['user', 'user', 'user']
assert config._cfgimpl_value_owners['string'] == 'user'
config.string = []
config.unwrap_from_path("string").reset(config)
# assert config.string == ["string"]
assert config._cfgimpl_value_owners['string'] == ['default']
assert config._cfgimpl_value_owners['string'] == 'default'
raises(ConfigError, "config.string = None")
def test_default_with_multi():
@ -111,10 +111,10 @@ def test_access_with_multi_default():
s = StrOption("string", "", default=["string"], multi=True)
descr = OptionDescription("options", "", [s])
config = Config(descr)
assert config._cfgimpl_value_owners["string"] == ['default']
assert config._cfgimpl_value_owners["string"] == 'default'
config.string = ["foo", "bar"]
assert config.string == ["foo", "bar"]
assert config._cfgimpl_value_owners["string"] == ['user', 'user']
assert config._cfgimpl_value_owners["string"] == 'user'
#def test_attribute_access_with_multi2():
# s = StrOption("string", "", default="string", multi=True)

View File

@ -25,7 +25,7 @@ from tiramisu.error import (PropertiesOptionError, ConfigError, NotFoundError,
AmbigousOptionError, ConflictConfigError, NoMatchingOptionFound,
MandatoryError, MethodCallError, NoValueReturned)
from tiramisu.option import (OptionDescription, Option, SymLinkOption,
group_types, Multi, apply_requires, Owner)
group_types, Multi, apply_requires)
# ______________________________________________________________________
# generic owner. 'default' is the general config owner after init time
@ -33,10 +33,11 @@ default_owner = 'user'
# ____________________________________________________________
class Config(object):
"properties attribute: the name of a property enables this property"
"main configuration management entry"
#properties attribute: the name of a property enables this property
_cfgimpl_properties = ['hidden', 'disabled']
_cfgimpl_permissive = []
"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_frozen = True
_cfgimpl_owner = default_owner
@ -87,13 +88,11 @@ class Config(object):
child=child)
self._cfgimpl_values[child._name] = childdef
self._cfgimpl_previous_values[child._name] = list(childdef)
self._cfgimpl_value_owners[child._name] = ['default' \
for i in range(len(child.getdefault() ))]
else:
childdef = child.getdefault()
self._cfgimpl_values[child._name] = childdef
self._cfgimpl_previous_values[child._name] = childdef
self._cfgimpl_value_owners[child._name] = 'default'
self._cfgimpl_value_owners[child._name] = 'default'
elif isinstance(child, OptionDescription):
self._validate_duplicates(child._children)
self._cfgimpl_values[child._name] = Config(child, parent=self)
@ -115,24 +114,13 @@ class Config(object):
if child.is_multi():
self._cfgimpl_values[child._name] = Multi(
copy(child.getdefault()), config=self, child=child)
self._cfgimpl_value_owners[child._name] = ['default' \
for i in range(len(child.getdefault() ))]
else:
self._cfgimpl_values[child._name] = copy(child.getdefault())
self._cfgimpl_value_owners[child._name] = 'default'
self._cfgimpl_value_owners[child._name] = 'default'
elif isinstance(child, OptionDescription):
if child._name not in self._cfgimpl_values:
self._cfgimpl_values[child._name] = Config(child, parent=self)
# def override(self, overrides):
# """
# overrides default values. This marks the overridden values as defaults.
# :param overrides: is a dictionary of path strings to values.
# """
# for name, value in overrides.iteritems():
# homeconfig, name = self._cfgimpl_get_home_by_path(name)
# homeconfig.setoption(name, value, 'default')
def cfgimpl_set_owner(self, owner):
":param owner: sets the default value for owner at the Config level"
self._cfgimpl_owner = owner
@ -254,8 +242,7 @@ class Config(object):
value = self._cfgimpl_values[name]
if (not opt_or_descr.is_frozen() or \
not opt_or_descr.is_forced_on_freeze()) and \
not opt_or_descr.is_default_owner(self, all_default=False):
#not opt_or_descr.getowner(self) == 'default':
not opt_or_descr.is_default_owner(self):
if opt_or_descr.is_multi():
if None not in value:
return value
@ -268,42 +255,9 @@ class Config(object):
pass
else:
if opt_or_descr.is_multi():
owners = copy(self._cfgimpl_value_owners[name])
self._cfgimpl_value_owners[name] = []
if not isinstance(result, list):
# for example, [1, 2, 3, None] -> [1, 2, 3, result]
_result = Multi([result], value.config, value.child)
for cpt in range(len(value)):
val = value[cpt]
if len(owners) > cpt:
if owners[cpt] == 'default':
_result.append(result)
self._cfgimpl_value_owners[name][cpt] = 'default'
else:
_result.append(val)
else:
_result.append(val)
self._cfgimpl_value_owners[name][cpt] = 'default'
else:
# for example, [1, None, 2, None] + [a, b, c, d]
# = [1, b, 2, d]
_result = Multi([], value.config, value.child)
for cpt in range(max(len(value), len(result))):
if len(value) > cpt:
val = value[cpt]
else:
val = ''
if len(result) > cpt:
rval = result[cpt]
if len(owners) > cpt:
if owners[cpt] == 'default':
_result.append(rval)
self._cfgimpl_value_owners[name][cpt] = 'default'
else:
_result.append(val)
else:
_result.append(rval)
self._cfgimpl_value_owners[name][cpt] = 'default'
result = [result]
_result = Multi(result, value.config, value.child)
else:
# this result **shall not** be a list
if isinstance(result, list):
@ -314,6 +268,7 @@ class Config(object):
raise ConfigError('invalid calculated value returned'
' for option {0}'.format(name))
self._cfgimpl_values[name] = _result
self._cfgimpl_value_owners[name] = 'default'
self._test_mandatory(name, opt_or_descr)
# frozen and force default
if not opt_or_descr.has_callback() and opt_or_descr.is_forced_on_freeze():
@ -347,16 +302,16 @@ class Config(object):
return getattr(homeconfig._cfgimpl_descr, path)
return getattr(self._cfgimpl_descr, path)
def __delattr__(self, name):
"if you use delattr you are responsible for all bad things happening"
if name.startswith('_cfgimpl_'):
del self.__dict__[name]
return
self._cfgimpl_value_owners[name] = 'default'
opt = getattr(self._cfgimpl_descr, name)
if isinstance(opt, OptionDescription):
raise AttributeError("can't option subgroup")
self._cfgimpl_values[name] = getattr(opt, 'default', None)
#def __delattr__(self, name):
# "if you use delattr you are responsible for all bad things happening"
# if name.startswith('_cfgimpl_'):
# del self.__dict__[name]
# return
# self._cfgimpl_value_owners[name] = 'default'
# opt = getattr(self._cfgimpl_descr, name)
# if isinstance(opt, OptionDescription):
# raise AttributeError("can't option subgroup")
# self._cfgimpl_values[name] = getattr(opt, 'default', None)
def setoption(self, name, value, who=None):
"""effectively modifies the value of an Option()
@ -377,14 +332,8 @@ class Config(object):
else:
raise ConfigError("invalid value for option:"
" {0} that is set to multi".format(name))
newowner = [who for i in range(len(value))]
else:
newowner = who
child.setoption(self, value, who)
if child.is_multi() and value == [] and who != 'default':
child.setowner(self, Owner(who))
else:
child.setowner(self, newowner)
child.setowner(self, who)
else:
homeconfig = self._cfgimpl_get_toplevel()
child.setoption(homeconfig, value, who)

View File

@ -47,15 +47,6 @@ group_types = ['default', 'family', 'group', 'master']
# ____________________________________________________________
# multi types
class Owner(str):
"an owner just for a multi Option that have no value set"
# we need a string that cannot be iterable
def __iter__(self):
raise StopIteration
def __len__(self):
return 0
class Multi(list):
"container that support items for the values of list (multi) options"
def __init__(self, lst, config, child):
@ -72,28 +63,21 @@ class Multi(list):
def setoption(self, value, key=None, who=None):
if who is None:
who = self.config._cfgimpl_owner
if not self.child._validate(value):
raise ConfigError("invalid value {0} "
"for option {1}".format(str(value), self.child._name))
if value != None:
if not self.child._validate(value):
raise ConfigError("invalid value {0} "
"for option {1}".format(str(value), self.child._name))
oldvalue = list(self)
oldowner = self.child.getowner(self.config)
if isinstance(oldowner, Owner):
oldowner = []
if key is None:
ret = super(Multi, self).append(value)
oldvalue.append(None)
oldowner.append(who)
else:
ret = super(Multi, self).__setitem__(key, value)
oldowner[key] = who
self.child.setowner(self.config, who)
self.config._cfgimpl_previous_values[self.child._name] = oldvalue
self.child.setowner(self.config, oldowner)
return ret
def pop(self, key):
oldowner = self.child.getowner(self.config)
oldowner.pop(key)
self.child.setowner(self.config, oldowner)
self.child.setowner(self.config, self.config._cfgimpl_owner)
super(Multi, self).pop(key)
# ____________________________________________________________
#
@ -219,10 +203,9 @@ class Option(HiddenBaseType, DisabledBaseType):
which is allowable here
"""
name = self._name
if self.is_multi():
if not type(owner) == list and not isinstance(owner, Owner):
raise ConfigError("invalid owner for multi "
"option: {0}".format(name))
if not type(owner) == str:
raise ConfigError("invalid type for owner option: {0}".format(
name))
config._cfgimpl_value_owners[name] = owner
def getowner(self, config):
@ -236,13 +219,14 @@ class Option(HiddenBaseType, DisabledBaseType):
if self.is_multi():
if idx is not None:
defval = self.getdefault()
value = getattr(config, self._name)
# if the default is ['a', 'b', 'c']
if len(defval) > idx:
# and idx = 4 -> there is actually no such value in the default
value.setoption(default_multi, idx, who='default')
else:
# and idx = 2 -> there is a value in the default
value.setoption(defval[idx], idx, who='default')
else:
# and idx = 4 -> there is actually no such value in the default
value.setoption(self.default_multi, idx, who='default')
else:
value = Multi(self.getdefault(), config, self)
config.setoption(self._name, value, 'default')
@ -250,34 +234,13 @@ class Option(HiddenBaseType, DisabledBaseType):
value = self.getdefault()
config.setoption(self._name, value, 'default')
def is_default_owner(self, config, all_default=True, at_index=None):
def is_default_owner(self, config):
"""
:param config: *must* be only the **parent** config
(not the toplevel config)
:param all_default: only for multi options, if True and the owner list
has something else than "default" returns False, if False and the owner
list has at least one "default" owner, returns True
:param at_index: only for multi options, checks owner at specified
index
:return: boolean
"""
if self.is_multi():
owners = self.getowner(config)
if at_index:
return owners[at_index] == 'default'
for owner in owners:
if all_default and owner != 'default':
return False
if not all_default and owner == 'default':
return True
if all_default or owners == []:
return True
else:
return False
else:
if at_index:
raise ValueError('index specified for a not multi option')
return self.getowner(config) == 'default'
return self.getowner(config) == 'default'
def setoption(self, config, value, who):
"""changes the option's value with the value_owner's who
@ -405,22 +368,17 @@ class NetmaskOption(Option):
# by now the validation is nothing but a string, use IPy instead
return isinstance(value, str)
class ArbitraryOption(Option):
def __init__(self, name, doc, default=None, defaultfactory=None,
requires=None, multi=False, mandatory=False):
super(ArbitraryOption, self).__init__(name, doc, requires=requires,
multi=multi, mandatory=mandatory)
self.defaultfactory = defaultfactory
if defaultfactory is not None:
assert default is None
#class ArbitraryOption(Option):
# def __init__(self, name, doc, default=None, defaultfactory=None,
# requires=None, multi=False, mandatory=False):
# super(ArbitraryOption, self).__init__(name, doc, requires=requires,
# multi=multi, mandatory=mandatory)
# self.defaultfactory = defaultfactory
# if defaultfactory is not None:
# assert default is None
def _validate(self, value):
return True
def getdefault(self):
if self.defaultfactory is not None:
return self.defaultfactory()
return self.default
# def _validate(self, value):
# return True
class OptionDescription(HiddenBaseType, DisabledBaseType):
"Config's schema (organisation) and container of Options"

View File

@ -14,13 +14,13 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# The original `Config` design model is unproudly borrowed from
# The original `Config` design model is unproudly borrowed from
# the rough gus of pypy: pypy: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence
from tiramisu.config import Config
from tiramisu.option import (OptionDescription, Option, ChoiceOption, BoolOption,
FloatOption, StrOption, IntOption, IPOption, NetmaskOption,
ArbitraryOption, group_types, apply_requires)
from tiramisu.option import (OptionDescription, Option, ChoiceOption, BoolOption,
FloatOption, StrOption, IntOption, IPOption, NetmaskOption,
group_types, apply_requires)
# ____________________________________________________________
# reverse factory
@ -38,7 +38,7 @@ def reverse_from_paths(data):
"dummy -> Option('dummy')"
if isinstance(value, list):
return _build_map[type(value[0])](name, '', multi=True, default=value)
else:
else:
return _build_map[type(value)](name, '', default=value)
def build_options(data):
@ -51,7 +51,7 @@ def reverse_from_paths(data):
"config.gc.dummy -> config.gc"
if "." in pathname:
return ".".join(pathname.split('.')[:-1])
# no parent except rootconfig, naturally returns None
# no parent except rootconfig, naturally returns None
def subgroups(pathname):
"config.gc.dummy.bool -> [config.gc, config.gc.dummy]"
@ -60,13 +60,13 @@ def reverse_from_paths(data):
while group is not None:
parents.append(group)
group = parent(group)
return parents
return parents
def build_option_descriptions(data):
all_groups = []
for key in data.keys():
for group in subgroups(key):
# so group is unique in the list
# so group is unique in the list
if group not in all_groups:
all_groups.append(group)
for group in all_groups:
@ -126,4 +126,3 @@ class extend(type):
setattr(cls, key, value)
# ____________________________________________________________