Values validate now value

This commit is contained in:
Emmanuel Garette 2013-04-11 11:30:58 +02:00
parent 0c5ab9df18
commit 26568dc45a
7 changed files with 52 additions and 208 deletions

View file

@ -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)")
#____________________________________________________________

View file

@ -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'

View file

@ -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"

View file

@ -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, ))

View file

@ -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)

View file

@ -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)
# ____________________________________________________________

View file

@ -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)