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') config.cfgimpl_get_settings().enable_property('freeze')
dummy = config.unwrap_from_path('gc.dummy') dummy = config.unwrap_from_path('gc.dummy')
config.cfgimpl_get_settings().add_property('frozen', 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"] assert config.t1 == ["a", "b", "a", "b"]
# ____________________________________________________________ # ____________________________________________________________
def test_setoption_from_option(): #def test_setoption_from_option():
"a setoption directly from the option is **not** a good practice" # "a setoption directly from the option is **not** a good practice"
booloption = BoolOption('bool', 'Test boolean option', default=True) # booloption = BoolOption('bool', 'Test boolean option', default=True)
descr = OptionDescription('descr', '', [booloption]) # descr = OptionDescription('descr', '', [booloption])
cfg = Config(descr) # cfg = Config(descr)
booloption.setoption(cfg, False) # booloption.setoption(cfg, False)
assert cfg.bool == False # assert cfg.bool == False
#____________________________________________________________ #____________________________________________________________
def test_dwim_set(): def test_dwim_set():
descr = OptionDescription("opt", "", [ descr = OptionDescription("opt", "", [
@ -347,18 +347,18 @@ def test_set_symlink_option():
## assert config.gc.dummy == True ## assert config.gc.dummy == True
#____________________________________________________________ #____________________________________________________________
def test_accepts_multiple_changes_from_option(): #def test_accepts_multiple_changes_from_option():
s = StrOption("string", "", default="string") # s = StrOption("string", "", default="string")
descr = OptionDescription("options", "", [s]) # descr = OptionDescription("options", "", [s])
config = Config(descr) # config = Config(descr)
config.string = "egg" # config.string = "egg"
assert s.getdefault() == "string" # assert s.getdefault() == "string"
assert config.string == "egg" # assert config.string == "egg"
s.setoption(config, 'blah') # s.setoption(config, 'blah')
assert s.getdefault() == "string" # assert s.getdefault() == "string"
assert config.string == "blah" # assert config.string == "blah"
s.setoption(config, 'bol') # s.setoption(config, 'bol')
assert config.string == 'bol' # assert config.string == 'bol'
def test_allow_multiple_changes_from_config(): def test_allow_multiple_changes_from_config():
""" """
@ -370,8 +370,8 @@ def test_allow_multiple_changes_from_config():
suboption = OptionDescription("bip", "", [s2]) suboption = OptionDescription("bip", "", [s2])
descr = OptionDescription("options", "", [s, suboption]) descr = OptionDescription("options", "", [s, suboption])
config = Config(descr) config = Config(descr)
config.setoption("string", 'blah', owners.user) config.setoption("string", s, 'blah')
config.setoption("string", "oh", owners.user) config.setoption("string", s, "oh")
assert config.string == "oh" assert config.string == "oh"
config.set(string2= 'blah') config.set(string2= 'blah')
assert config.bip.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, from tiramisu.error import (PropertiesOptionError, NotFoundError,
AmbigousOptionError, NoMatchingOptionFound, MandatoryError) AmbigousOptionError, NoMatchingOptionFound, MandatoryError)
from tiramisu.option import OptionDescription, Option, SymLinkOption 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 from tiramisu.value import Values
@ -71,9 +71,12 @@ class SubConfig(object):
if '.' in name: if '.' in name:
homeconfig, name = self.cfgimpl_get_home_by_path(name) homeconfig, name = self.cfgimpl_get_home_by_path(name)
return homeconfig.__setattr__(name, value) 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._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): def _validate(self, name, opt_or_descr, force_permissive=False):
"validation for the setattr and the getattr" "validation for the setattr and the getattr"
@ -135,12 +138,26 @@ class SubConfig(object):
return self.cfgimpl_get_values()._getitem(opt_or_descr, return self.cfgimpl_get_values()._getitem(opt_or_descr,
force_properties=force_properties) force_properties=force_properties)
def setoption(self, name, value, who=None): def setoption(self, name, child, value):
"""effectively modifies the value of an Option() """effectively modifies the value of an Option()
(typically called by the __setattr__) (typically called by the __setattr__)
""" """
child = getattr(self._cfgimpl_descr, name) setting = self.cfgimpl_get_settings()
child.setoption(self, value) #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): def cfgimpl_get_home_by_path(self, path, force_permissive=False, force_properties=None):
""":returns: tuple (config, name)""" """:returns: tuple (config, name)"""
@ -393,7 +410,6 @@ class Config(SubConfig):
:param kwargs: dict of name strings to values. :param kwargs: dict of name strings to values.
""" """
#opts, paths = self.cfgimpl_get_description()._cache_paths #opts, paths = self.cfgimpl_get_description()._cache_paths
#FIXME _validate pour apply_requires ?
all_paths = [p.split(".") for p in self.getpaths(allpaths=True)] all_paths = [p.split(".") for p in self.getpaths(allpaths=True)]
for key, value in kwargs.iteritems(): for key, value in kwargs.iteritems():
key_p = key.split('.') key_p = key.split('.')
@ -407,7 +423,8 @@ class Config(SubConfig):
pass pass
except Exception, e: except Exception, e:
raise e # HiddenOptionError or DisabledOptionError raise e # HiddenOptionError or DisabledOptionError
homeconfig.setoption(name, value) child = getattr(homeconfig._cfgimpl_descr, name)
homeconfig.setoption(name, child, value)
elif len(candidates) > 1: elif len(candidates) > 1:
raise AmbigousOptionError( raise AmbigousOptionError(
'more than one option that ends with %s' % (key, )) '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) 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): def getkey(self, value):
return value return value
@ -330,8 +308,7 @@ class SymLinkOption(object):
self._name = name self._name = name
self.opt = opt self.opt = opt
def setoption(self, config, value): def setoption(self, context, value):
context = config.cfgimpl_get_context()
path = context.cfgimpl_get_description().get_path_by_opt(self.opt) path = context.cfgimpl_get_description().get_path_by_opt(self.opt)
setattr(context, path, value) 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 return value
def __setitem__(self, opt, 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.is_multi():
if opt.multitype == multitypes.master: if opt.multitype == multitypes.master:
masterlen = len(value) masterlen = len(value)