diff --git a/test/test_config.py b/test/test_config.py index 865ef70..e7c5192 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -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() diff --git a/test/test_config_api.py b/test/test_config_api.py index 5d67413..3695049 100644 --- a/test/test_config_api.py +++ b/test/test_config_api.py @@ -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" diff --git a/test/test_option_default.py b/test/test_option_default.py index 5b12d6c..3b48770 100644 --- a/test/test_option_default.py +++ b/test/test_option_default.py @@ -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] diff --git a/test/test_option_setting.py b/test/test_option_setting.py index 9fdee42..f7a8903 100644 --- a/test/test_option_setting.py +++ b/test/test_option_setting.py @@ -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) diff --git a/tiramisu/config.py b/tiramisu/config.py index 2a8aeee..e97323e 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -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) diff --git a/tiramisu/option.py b/tiramisu/option.py index 3461bf5..fe0a619 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -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" diff --git a/tiramisu/tool.py b/tiramisu/tool.py index b535e90..9f082bf 100644 --- a/tiramisu/tool.py +++ b/tiramisu/tool.py @@ -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) # ____________________________________________________________ -