diff --git a/test/test_option_consistency.py b/test/test_option_consistency.py index 8bc9b10..e241f29 100644 --- a/test/test_option_consistency.py +++ b/test/test_option_consistency.py @@ -253,5 +253,5 @@ def test_freeze_and_has_callback_with_setoption(): config.cfgimpl_get_settings().enable_property('freeze') dummy = config.unwrap_from_path('gc.dummy') config.cfgimpl_get_settings().add_property('frozen', dummy) - raises(TypeError, "config.gc.setoption('dummy', True, 'gen_config')") + raises(TypeError, "config.gc.setoption('dummy', descr.gc.dummy, True)") #____________________________________________________________ diff --git a/test/test_option_setting.py b/test/test_option_setting.py index 2d41cc2..e0af336 100644 --- a/test/test_option_setting.py +++ b/test/test_option_setting.py @@ -250,13 +250,13 @@ def test_choice_access_with_multi(): assert config.t1 == ["a", "b", "a", "b"] # ____________________________________________________________ -def test_setoption_from_option(): - "a setoption directly from the option is **not** a good practice" - booloption = BoolOption('bool', 'Test boolean option', default=True) - descr = OptionDescription('descr', '', [booloption]) - cfg = Config(descr) - booloption.setoption(cfg, False) - assert cfg.bool == False +#def test_setoption_from_option(): +# "a setoption directly from the option is **not** a good practice" +# booloption = BoolOption('bool', 'Test boolean option', default=True) +# descr = OptionDescription('descr', '', [booloption]) +# cfg = Config(descr) +# booloption.setoption(cfg, False) +# assert cfg.bool == False #____________________________________________________________ def test_dwim_set(): descr = OptionDescription("opt", "", [ @@ -347,18 +347,18 @@ def test_set_symlink_option(): ## assert config.gc.dummy == True #____________________________________________________________ -def test_accepts_multiple_changes_from_option(): - s = StrOption("string", "", default="string") - descr = OptionDescription("options", "", [s]) - config = Config(descr) - config.string = "egg" - assert s.getdefault() == "string" - assert config.string == "egg" - s.setoption(config, 'blah') - assert s.getdefault() == "string" - assert config.string == "blah" - s.setoption(config, 'bol') - assert config.string == 'bol' +#def test_accepts_multiple_changes_from_option(): +# s = StrOption("string", "", default="string") +# descr = OptionDescription("options", "", [s]) +# config = Config(descr) +# config.string = "egg" +# assert s.getdefault() == "string" +# assert config.string == "egg" +# s.setoption(config, 'blah') +# assert s.getdefault() == "string" +# assert config.string == "blah" +# s.setoption(config, 'bol') +# assert config.string == 'bol' def test_allow_multiple_changes_from_config(): """ @@ -370,8 +370,8 @@ def test_allow_multiple_changes_from_config(): suboption = OptionDescription("bip", "", [s2]) descr = OptionDescription("options", "", [s, suboption]) config = Config(descr) - config.setoption("string", 'blah', owners.user) - config.setoption("string", "oh", owners.user) + config.setoption("string", s, 'blah') + config.setoption("string", s, "oh") assert config.string == "oh" config.set(string2= 'blah') assert config.bip.string2 == 'blah' diff --git a/test/test_tool.py b/test/test_tool.py deleted file mode 100644 index 8620bc4..0000000 --- a/test/test_tool.py +++ /dev/null @@ -1,26 +0,0 @@ -#this test is much more to test that **it's there** and answers attribute access -import autopath -from py.test import raises - -from tool import extend - -class A: - a = 'titi' - def tarte(self): - return "tart" -class B: - __metaclass__ = extend - - def to_rst(self): - return "hello" - -B.extend(A) - -a = B() - -def test_extendable(): - assert a.a == 'titi' - assert a.tarte() == 'tart' - assert a.to_rst() == "hello" - - diff --git a/tiramisu/config.py b/tiramisu/config.py index 4440459..dfc3560 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -24,7 +24,7 @@ from tiramisu.error import (PropertiesOptionError, NotFoundError, AmbigousOptionError, NoMatchingOptionFound, MandatoryError) from tiramisu.option import OptionDescription, Option, SymLinkOption -from tiramisu.setting import groups, Setting +from tiramisu.setting import groups, Setting, apply_requires from tiramisu.value import Values @@ -71,9 +71,12 @@ class SubConfig(object): if '.' in name: homeconfig, name = self.cfgimpl_get_home_by_path(name) return homeconfig.__setattr__(name, value) - if type(getattr(self._cfgimpl_descr, name)) != SymLinkOption: + child = getattr(self._cfgimpl_descr, name) + if type(child) != SymLinkOption: self._validate(name, getattr(self._cfgimpl_descr, name), force_permissive=force_permissive) - self.setoption(name, value) + self.setoption(name, child, value) + else: + child.setoption(self.cfgimpl_get_context(), value) def _validate(self, name, opt_or_descr, force_permissive=False): "validation for the setattr and the getattr" @@ -135,12 +138,26 @@ class SubConfig(object): return self.cfgimpl_get_values()._getitem(opt_or_descr, force_properties=force_properties) - def setoption(self, name, value, who=None): + def setoption(self, name, child, value): """effectively modifies the value of an Option() (typically called by the __setattr__) """ - child = getattr(self._cfgimpl_descr, name) - child.setoption(self, value) + setting = self.cfgimpl_get_settings() + #needed ? + apply_requires(child, self) + #needed to ? + if child not in self._cfgimpl_descr._children[1]: + raise AttributeError('unknown option %s' % (name)) + + if setting.has_property('everything_frozen'): + raise TypeError("cannot set a value to the option {} if the whole " + "config has been frozen".format(name)) + + if setting.has_property('frozen') and setting.has_property('frozen', + child, is_apply_req=False): + raise TypeError('cannot change the value to %s for ' + 'option %s this option is frozen' % (str(value), name)) + self.cfgimpl_get_values()[child] = value def cfgimpl_get_home_by_path(self, path, force_permissive=False, force_properties=None): """:returns: tuple (config, name)""" @@ -393,7 +410,6 @@ class Config(SubConfig): :param kwargs: dict of name strings to values. """ #opts, paths = self.cfgimpl_get_description()._cache_paths - #FIXME _validate pour apply_requires ? all_paths = [p.split(".") for p in self.getpaths(allpaths=True)] for key, value in kwargs.iteritems(): key_p = key.split('.') @@ -407,7 +423,8 @@ class Config(SubConfig): pass except Exception, e: raise e # HiddenOptionError or DisabledOptionError - homeconfig.setoption(name, value) + child = getattr(homeconfig._cfgimpl_descr, name) + homeconfig.setoption(name, child, value) elif len(candidates) > 1: raise AmbigousOptionError( 'more than one option that ends with %s' % (key, )) diff --git a/tiramisu/option.py b/tiramisu/option.py index 9bdd4a5..befeec7 100644 --- a/tiramisu/option.py +++ b/tiramisu/option.py @@ -221,28 +221,6 @@ class Option(BaseInformation): """ config._cfgimpl_context._cfgimpl_values.reset(self) - def setoption(self, config, value): - """changes the option's value with the value_owner's who - :param config: the parent config is necessary here to store the value - """ - name = self._name - setting = config.cfgimpl_get_settings() - if not self.validate(value, setting.has_property('validator')): - raise ConfigError('invalid value %s for option %s' % (value, name)) - if self not in config._cfgimpl_descr._children[1]: - raise AttributeError('unknown option %s' % (name)) - - if setting.has_property('everything_frozen'): - raise TypeError("cannot set a value to the option {} if the whole " - "config has been frozen".format(name)) - - if setting.has_property('frozen') and setting.has_property('frozen', - self, False): - raise TypeError('cannot change the value to %s for ' - 'option %s this option is frozen' % (str(value), name)) - #apply_requires(self, config) - config.cfgimpl_get_values()[self] = value - def getkey(self, value): return value @@ -330,8 +308,7 @@ class SymLinkOption(object): self._name = name self.opt = opt - def setoption(self, config, value): - context = config.cfgimpl_get_context() + def setoption(self, context, value): path = context.cfgimpl_get_description().get_path_by_opt(self.opt) setattr(context, path, value) diff --git a/tiramisu/tool.py b/tiramisu/tool.py deleted file mode 100644 index e10be70..0000000 --- a/tiramisu/tool.py +++ /dev/null @@ -1,128 +0,0 @@ -# Copyright (C) 2012 Team tiramisu (see AUTHORS for all contributors) -# -# This program is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation; either version 2 of the License, or -# (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# 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 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, - apply_requires) - -# ____________________________________________________________ -# reverse factory -# XXX HAAAAAAAAAAAACK (but possibly a good one) -#def reverse_from_paths(data): -# "rebuilds a (fake) data structure from an unflatten `make_dict()` result" -# # ____________________________________________________________ -# _build_map = { -# bool: BoolOption, -# int: IntOption, -# float: FloatOption, -# str: StrOption, -# } -# def option_factory(name, value): -# "dummy -> Option('dummy')" -# if isinstance(value, list): -# return _build_map[type(value[0])](name, '', multi=True, default=value) -# else: -# return _build_map[type(value)](name, '', default=value) - -# def build_options(data): -# "config.gc.dummy -> Option('dummy')" -# for key, value in data.items(): -# name = key.split('.')[-1] -# yield (key, option_factory(name, value)) -# # ____________________________________________________________ -# def parent(pathname): -# "config.gc.dummy -> config.gc" -# if "." in pathname: -# return ".".join(pathname.split('.')[:-1]) -# # no parent except rootconfig, naturally returns None - -# def subgroups(pathname): -# "config.gc.dummy.bool -> [config.gc, config.gc.dummy]" -# group = parent(pathname) -# parents =[] -# while group is not None: -# parents.append(group) -# group = parent(group) -# 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 -# if group not in all_groups: -# all_groups.append(group) -# for group in all_groups: -# name = group.split('.')[-1] -# yield (group, OptionDescription(name, '', [])) -# # ____________________________________________________________ -# descr = OptionDescription('tiramisu', 'fake rebuild structure', []) -# cfg = Config(descr) -# # add descrs in cfg -# def compare(a, b): -# l1 = a.split(".") -# l2 = b.split(".") -# if len(l1) < len(l2): -# return -1 -# elif len(l1) > len(l2): -# return 1 -# else: -# return 0 -# grps = list(build_option_descriptions(data)) -# groups = dict(grps) -# grp_paths = [pathname for pathname, opt_descr in grps] -# grp_paths.sort(compare) -# for grp in grp_paths: -# if not "." in grp: -# cfg._cfgimpl_descr.add_child(groups[grp]) -# cfg.cfgimpl_update() -# else: -# parentdescr = cfg.unwrap_from_path(parent(grp)) -# parentdescr.add_child(groups[grp]) -# getattr(cfg, parent(grp)).cfgimpl_update() -# # add options in descrs -# for pathname, opt in build_options(data): -# current_group_name = parent(pathname) -# if current_group_name == None: -# cfg._cfgimpl_descr.add_child(opt) -# cfg.cfgimpl_update() -# else: -# curr_grp = groups[current_group_name] -# curr_grp.add_child(opt) -# getattr(cfg, current_group_name).cfgimpl_update() - -# return cfg -# ____________________________________________________________ -# extendable type -class extend(type): - """ - A magic trick for classes, which lets you add methods or attributes to a - class - """ - def extend(cls, extclass): - bases = list(extclass.__bases__) - bases.append(extclass) - for cl in bases: - for key, value in cl.__dict__.items(): - if key == '__module__': - continue - setattr(cls, key, value) - -# ____________________________________________________________ diff --git a/tiramisu/value.py b/tiramisu/value.py index 74022b3..1a7e9e2 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -148,6 +148,10 @@ class Values(object): 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 opt.is_multi(): if opt.multitype == multitypes.master: masterlen = len(value)