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,8 +88,6 @@ 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
@ -115,8 +114,6 @@ 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'
@ -124,15 +121,6 @@ class Config(object):
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 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,33 +234,12 @@ 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'
def setoption(self, config, value, 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

@ -20,7 +20,7 @@
from tiramisu.config import Config
from tiramisu.option import (OptionDescription, Option, ChoiceOption, BoolOption,
FloatOption, StrOption, IntOption, IPOption, NetmaskOption,
ArbitraryOption, group_types, apply_requires)
group_types, apply_requires)
# ____________________________________________________________
# reverse factory
@ -126,4 +126,3 @@ class extend(type):
setattr(cls, key, value)
# ____________________________________________________________