Values validate now value
This commit is contained in:
parent
0c5ab9df18
commit
26568dc45a
7 changed files with 52 additions and 208 deletions
|
@ -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)")
|
||||
#____________________________________________________________
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
|
@ -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, ))
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
128
tiramisu/tool.py
128
tiramisu/tool.py
|
@ -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)
|
||||
|
||||
# ____________________________________________________________
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue