properties validation not in setting and now launch when modify multi

This commit is contained in:
Emmanuel Garette 2013-04-17 21:33:34 +02:00
parent 656b751995
commit 3170237c8e
8 changed files with 258 additions and 151 deletions

138
test/test_freeze.py Normal file
View File

@ -0,0 +1,138 @@
# coding: utf-8
"frozen and hidden values"
import autopath
from tiramisu.option import ChoiceOption, BoolOption, IntOption, FloatOption, \
StrOption, OptionDescription
from tiramisu.config import Config
from tiramisu.error import PropertiesOptionError
#____________________________________________________________
#freeze
def make_description_freeze():
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
gcdummy = BoolOption('dummy', 'dummy', default=False)
objspaceoption = ChoiceOption('objspace', 'Object space',
('std', 'thunk'), 'std')
booloption = BoolOption('bool', 'Test boolean option', default=True)
intoption = IntOption('int', 'Test int option', default=0)
floatoption = FloatOption('float', 'Test float option', default=2.3)
stroption = StrOption('str', 'Test string option', default="abc")
boolop = BoolOption('boolop', 'Test boolean option op', default=[True], multi=True)
wantref_option = BoolOption('wantref', 'Test requires', default=False,
requires=(('boolop', True, 'hidden'),))
wantframework_option = BoolOption('wantframework', 'Test requires',
default=False,
requires=(('boolop', True, 'hidden'),))
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
descr = OptionDescription('tiramisu', '', [gcgroup, booloption, objspaceoption,
wantref_option, stroption,
wantframework_option,
intoption, boolop])
return descr
def test_freeze_whole_config():
descr = make_description_freeze()
conf = Config(descr)
setting = conf.cfgimpl_get_settings()
setting.read_write()
setting.enable_property('everything_frozen')
assert conf.gc.dummy is False
prop = []
try:
conf.gc.dummy = True
except PropertiesOptionError, err:
prop = err.proptype
assert 'frozen' in prop
setting.disable_property('everything_frozen')
conf.gc.dummy = True
assert conf.gc.dummy is True
def test_freeze_one_option():
"freeze an option "
descr = make_description_freeze()
conf = Config(descr)
setting = conf.cfgimpl_get_settings()
setting.read_write()
#freeze only one option
dummy = conf.unwrap_from_path('gc.dummy')
setting.add_property('frozen', dummy)
assert conf.gc.dummy is False
prop = []
try:
conf.gc.dummy = True
except PropertiesOptionError, err:
prop = err.proptype
assert 'frozen' in prop
def test_frozen_value():
"setattr a frozen value at the config level"
s = StrOption("string", "", default="string")
descr = OptionDescription("options", "", [s])
config = Config(descr)
setting = config.cfgimpl_get_settings()
setting.read_write()
setting.enable_property('frozen')
setting.add_property('frozen', s)
prop = []
try:
config.string = "egg"
except PropertiesOptionError, err:
prop = err.proptype
assert 'frozen' in prop
def test_freeze():
"freeze a whole configuration object"
descr = make_description_freeze()
conf = Config(descr)
setting = conf.cfgimpl_get_settings()
setting.read_write()
setting.enable_property('frozen')
name = conf.unwrap_from_path("gc.name")
setting.add_property('frozen', name)
prop = []
try:
conf.gc.name = 'framework'
except PropertiesOptionError, err:
prop = err.proptype
assert 'frozen' in prop
def test_freeze_multi():
descr = make_description_freeze()
conf = Config(descr)
setting = conf.cfgimpl_get_settings()
setting.read_write()
setting.enable_property('frozen')
obj = conf.unwrap_from_path('boolop')
setting.add_property('frozen', obj)
prop = []
try:
conf.boolop = [True]
except PropertiesOptionError, err:
prop = err.proptype
assert 'frozen' in prop
def test_freeze_get_multi():
descr = make_description_freeze()
conf = Config(descr)
setting = conf.cfgimpl_get_settings()
setting.read_write()
setting.enable_property('frozen')
valmulti = conf.boolop
valmulti.append(False)
obj = conf.unwrap_from_path('boolop')
setting.add_property('frozen', obj)
prop = []
try:
valmulti.append(False)
except PropertiesOptionError, err:
prop = err.proptype
assert 'frozen' in prop

View File

@ -150,6 +150,15 @@ def test_mandatory_multi_empty():
assert 'mandatory' in prop assert 'mandatory' in prop
def test_mandatory_multi_append():
descr = make_description()
config = Config(descr)
setting = config.cfgimpl_get_settings()
config.str3 = ['yes']
setting.read_write()
config.str3.append(None)
def test_mandatory_disabled(): def test_mandatory_disabled():
descr = make_description() descr = make_description()
config = Config(descr) config = Config(descr)
@ -212,3 +221,16 @@ def test_mandatory_warnings_disabled():
assert list(mandatory_warnings(config)) == ['str', 'str1', 'str2', 'str3'] assert list(mandatory_warnings(config)) == ['str', 'str1', 'str2', 'str3']
setting.add_property('disabled', descr.str) setting.add_property('disabled', descr.str)
assert list(mandatory_warnings(config)) == ['str1', 'str2', 'str3'] assert list(mandatory_warnings(config)) == ['str1', 'str2', 'str3']
def test_mandatory_warnings_frozen():
descr = make_description()
config = Config(descr)
config.str = ''
setting = config.cfgimpl_get_settings()
setting.read_write()
config.str
assert list(mandatory_warnings(config)) == ['str', 'str1', 'str2', 'str3']
setting.add_property('frozen', descr.str)
setting.read_only()
assert list(mandatory_warnings(config)) == ['str', 'str1', 'str2', 'str3']

View File

@ -3,6 +3,7 @@ from py.test import raises
from tiramisu.config import * from tiramisu.config import *
from tiramisu.option import * from tiramisu.option import *
from error import ConfigError
def make_description(): def make_description():
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref') gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
@ -242,7 +243,7 @@ def test_has_callback():
dummy = config.unwrap_from_path('gc.dummy') dummy = config.unwrap_from_path('gc.dummy')
setting.enable_property('freeze') setting.enable_property('freeze')
setting.add_property('frozen', dummy) setting.add_property('frozen', dummy)
raises(ConfigError, "config.gc.dummy = True") raises(PropertiesOptionError, "config.gc.dummy = True")
def test_freeze_and_has_callback_with_setoption(): def test_freeze_and_has_callback_with_setoption():
descr = make_description_callback() descr = make_description_callback()
@ -253,5 +254,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(ConfigError, "config.gc.setoption('dummy', descr.gc.dummy, True)") raises(PropertiesOptionError, "config.gc.setoption('dummy', descr.gc.dummy, True)")
#____________________________________________________________ #____________________________________________________________

View File

@ -3,8 +3,11 @@
import autopath import autopath
from py.test import raises from py.test import raises
from tiramisu.config import * from tiramisu.config import Config
from tiramisu.option import * from tiramisu.option import ChoiceOption, BoolOption, IntOption, FloatOption, \
StrOption, OptionDescription
from tiramisu.error import PropertiesOptionError
def make_description(): def make_description():
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref') gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
@ -33,71 +36,8 @@ def make_description():
wantframework_option, wantframework_option,
intoption]) intoption])
return descr return descr
#____________________________________________________________
#freeze
def make_description_freeze():
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
gcdummy = BoolOption('dummy', 'dummy', default=False)
objspaceoption = ChoiceOption('objspace', 'Object space',
('std', 'thunk'), 'std')
booloption = BoolOption('bool', 'Test boolean option', default=True)
intoption = IntOption('int', 'Test int option', default=0)
floatoption = FloatOption('float', 'Test float option', default=2.3)
stroption = StrOption('str', 'Test string option', default="abc")
boolop = BoolOption('boolop', 'Test boolean option op', default=True)
wantref_option = BoolOption('wantref', 'Test requires', default=False,
requires=(('boolop', True, 'hidden'),))
wantframework_option = BoolOption('wantframework', 'Test requires',
default=False,
requires=(('boolop', True, 'hidden'),))
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
descr = OptionDescription('tiramisu', '', [gcgroup, booloption, objspaceoption,
wantref_option, stroption,
wantframework_option,
intoption, boolop])
return descr
def test_freeze_whole_config():
descr = make_description_freeze()
conf = Config(descr)
settings = conf.cfgimpl_get_settings()
settings.enable_property('everything_frozen')
assert conf.gc.dummy == False
raises(ConfigError, "conf.gc.dummy = True")
settings.disable_property('everything_frozen')
conf.gc.dummy = True
assert conf.gc.dummy == True
def test_freeze_one_option():
"freeze an option "
descr = make_description_freeze()
conf = Config(descr)
setting = conf.cfgimpl_get_settings()
setting.read_write()
#freeze only one option
dummy = conf.unwrap_from_path('gc.dummy')
conf.gc.cfgimpl_get_settings().add_property('frozen', dummy)
assert conf.gc.dummy == False
raises(ConfigError, "conf.gc.dummy = True")
def test_frozen_value():
"setattr a frozen value at the config level"
s = StrOption("string", "", default="string")
descr = OptionDescription("options", "", [s])
config = Config(descr)
settings = config.cfgimpl_get_settings().enable_property('frozen')
config.cfgimpl_get_settings().add_property('frozen', s)
raises(ConfigError, 'config.string = "egg"')
def test_freeze():
"freeze a whole configuration object"
descr = make_description()
conf = Config(descr)
settings = conf.cfgimpl_get_settings().enable_property('frozen')
name = conf.unwrap_from_path("gc.name")
conf.cfgimpl_get_settings().add_property('frozen', name)
raises(ConfigError, "conf.gc.name = 'framework'")
# ____________________________________________________________ # ____________________________________________________________
def test_is_hidden(): def test_is_hidden():
descr = make_description() descr = make_description()
@ -110,9 +50,7 @@ def test_is_hidden():
raises(PropertiesOptionError, "config.gc.dummy == False") raises(PropertiesOptionError, "config.gc.dummy == False")
# getattr # getattr
raises(PropertiesOptionError, "config.gc.dummy") raises(PropertiesOptionError, "config.gc.dummy")
# I want to access to this option anyway
opt = config.unwrap_from_path("gc.dummy")
assert config.cfgimpl_get_values()[opt] == False
def test_group_is_hidden(): def test_group_is_hidden():
descr = make_description() descr = make_description()
@ -120,7 +58,7 @@ def test_group_is_hidden():
setting = config.cfgimpl_get_settings() setting = config.cfgimpl_get_settings()
setting.read_write() setting.read_write()
gc = config.unwrap_from_path('gc') gc = config.unwrap_from_path('gc')
dummy = config.unwrap_from_path('gc.dummy') config.unwrap_from_path('gc.dummy')
config.cfgimpl_get_settings().add_property('hidden', gc) config.cfgimpl_get_settings().add_property('hidden', gc)
raises(PropertiesOptionError, "config.gc.dummy") raises(PropertiesOptionError, "config.gc.dummy")
assert config.cfgimpl_get_settings().has_property('hidden', gc) assert config.cfgimpl_get_settings().has_property('hidden', gc)
@ -132,6 +70,7 @@ def test_group_is_hidden():
#dummy est en hide #dummy est en hide
raises(PropertiesOptionError, "config.gc.dummy == False") raises(PropertiesOptionError, "config.gc.dummy == False")
def test_global_show(): def test_global_show():
descr = make_description() descr = make_description()
config = Config(descr) config = Config(descr)
@ -142,15 +81,16 @@ def test_global_show():
assert config.cfgimpl_get_settings().has_property('hidden', dummy) assert config.cfgimpl_get_settings().has_property('hidden', dummy)
raises(PropertiesOptionError, "config.gc.dummy == False") raises(PropertiesOptionError, "config.gc.dummy == False")
def test_with_many_subgroups(): def test_with_many_subgroups():
descr = make_description() descr = make_description()
config = Config(descr) config = Config(descr)
booltwo = config.unwrap_from_path('gc.subgroup.booltwo') booltwo = config.unwrap_from_path('gc.subgroup.booltwo')
assert not config.cfgimpl_get_settings().has_property('hidden', booltwo) assert not config.cfgimpl_get_settings().has_property('hidden', booltwo)
assert config.gc.subgroup.booltwo == False assert config.gc.subgroup.booltwo is False
config.cfgimpl_get_settings().add_property('hidden', booltwo) config.cfgimpl_get_settings().add_property('hidden', booltwo)
path = 'gc.subgroup.booltwo' path = 'gc.subgroup.booltwo'
homeconfig, name = config.cfgimpl_get_home_by_path(path) homeconfig, name = config.cfgimpl_get_home_by_path(path)
assert name == "booltwo" assert name == "booltwo"
option = getattr(homeconfig._cfgimpl_descr, name) getattr(homeconfig._cfgimpl_descr, name)
assert config.cfgimpl_get_settings().has_property('hidden', booltwo) assert config.cfgimpl_get_settings().has_property('hidden', booltwo)

View File

@ -21,8 +21,7 @@
# the whole pypy projet is under MIT licence # the whole pypy projet is under MIT licence
# ____________________________________________________________ # ____________________________________________________________
#from inspect import getmembers, ismethod #from inspect import getmembers, ismethod
from tiramisu.error import (PropertiesOptionError, ConfigError, from tiramisu.error import PropertiesOptionError, AmbigousOptionError
AmbigousOptionError)
from tiramisu.option import OptionDescription, Option, SymLinkOption from tiramisu.option import OptionDescription, Option, SymLinkOption
from tiramisu.setting import groups, Setting, apply_requires from tiramisu.setting import groups, Setting, apply_requires
from tiramisu.value import Values from tiramisu.value import Values
@ -79,49 +78,10 @@ class SubConfig(object):
return homeconfig.__setattr__(name, value) return homeconfig.__setattr__(name, value)
child = getattr(self._cfgimpl_descr, name) child = getattr(self._cfgimpl_descr, name)
if type(child) != SymLinkOption: if type(child) != SymLinkOption:
self._validate(name, getattr(self._cfgimpl_descr, name), value, self.setoption(name, child, value, force_permissive)
force_permissive=force_permissive)
self.setoption(name, child, value)
else: else:
child.setoption(self.cfgimpl_get_context(), value) child.setoption(self.cfgimpl_get_context(), value)
def _validate_descr(self, name, opt_or_descr, force_permissive=False, is_raise=True):
if not isinstance(opt_or_descr, Option) and \
not isinstance(opt_or_descr, OptionDescription):
raise TypeError(_('unexpected object: {0}').format(repr(opt_or_descr)))
properties = set(self.cfgimpl_get_settings().get_properties(opt_or_descr))
#remove this properties, those properties are validate in value/setting
properties = properties - set(['mandatory', 'frozen'])
set_properties = set(self.cfgimpl_get_settings().get_properties())
properties = properties & set_properties
if force_permissive is True or self.cfgimpl_get_settings().has_property('permissive', is_apply_req=False):
properties = properties - set(self.cfgimpl_get_settings().get_permissive())
properties = properties - set(self.cfgimpl_get_settings().get_permissive(opt_or_descr))
properties = list(properties)
if is_raise:
if properties != []:
raise PropertiesOptionError(_("trying to access"
" to an option named: {0} with properties"
" {1}").format(name, str(properties)),
properties)
else:
return properties
def _validate(self, name, opt_or_descr, value, force_permissive=False,
force_properties=None):
"validation for the setattr and the getattr"
properties = self._validate_descr(name, opt_or_descr,
force_permissive=force_permissive,
is_raise=False)
if self.cfgimpl_get_context().cfgimpl_get_values().is_mandatory_err(
opt_or_descr, value, force_properties=force_properties):
properties.append('mandatory')
if properties != []:
raise PropertiesOptionError(_("trying to access"
" to an option named: {0} with properties"
" {1}").format(name, str(properties)),
properties)
def __getattr__(self, name): def __getattr__(self, name):
return self._getattr(name) return self._getattr(name)
@ -142,14 +102,23 @@ class SubConfig(object):
return homeconfig._getattr(name, force_permissive=force_permissive, return homeconfig._getattr(name, force_permissive=force_permissive,
force_properties=force_properties, force_properties=force_properties,
validate=validate) validate=validate)
# special attributes
if name.startswith('_cfgimpl_'):
# if it were in __dict__ it would have been found already
object.__getattr__(self, name)
opt_or_descr = getattr(self._cfgimpl_descr, name) opt_or_descr = getattr(self._cfgimpl_descr, name)
# symlink options # symlink options
if type(opt_or_descr) == SymLinkOption: if isinstance(opt_or_descr, SymLinkOption):
rootconfig = self.cfgimpl_get_context() rootconfig = self.cfgimpl_get_context()
path = rootconfig.cfgimpl_get_description().get_path_by_opt(opt_or_descr.opt) path = rootconfig.cfgimpl_get_description().get_path_by_opt(opt_or_descr.opt)
return rootconfig._getattr(path, validate=validate) return rootconfig._getattr(path, validate=validate,
if isinstance(opt_or_descr, OptionDescription): force_properties=force_properties,
self._validate_descr(name, opt_or_descr, force_permissive=force_permissive) force_permissive=force_permissive)
elif isinstance(opt_or_descr, OptionDescription):
self.cfgimpl_get_settings().validate_properties(opt_or_descr,
True, False,
force_permissive=force_permissive,
force_properties=force_properties)
children = self.cfgimpl_get_description()._children children = self.cfgimpl_get_description()._children
if opt_or_descr not in children[1]: if opt_or_descr not in children[1]:
raise AttributeError(_("{0} with name {1} object has " raise AttributeError(_("{0} with name {1} object has "
@ -157,36 +126,22 @@ class SubConfig(object):
opt_or_descr._name, opt_or_descr._name,
name)) name))
return SubConfig(opt_or_descr, self._cfgimpl_context) return SubConfig(opt_or_descr, self._cfgimpl_context)
# special attributes else:
if name.startswith('_cfgimpl_'):
# if it were in __dict__ it would have been found already
object.__getattr__(self, name)
value = self.cfgimpl_get_values()._getitem(opt_or_descr, value = self.cfgimpl_get_values()._getitem(opt_or_descr,
validate=validate) validate=validate,
self._validate(name, opt_or_descr, value, force_properties=force_properties,
force_permissive=force_permissive, force_permissive=force_permissive)
force_properties=force_properties)
return value return value
def setoption(self, name, child, value): def setoption(self, name, child, value, force_permissive=False):
"""effectively modifies the value of an Option() """effectively modifies the value of an Option()
(typically called by the __setattr__) (typically called by the __setattr__)
""" """
setting = self.cfgimpl_get_settings()
#needed ? #needed ?
apply_requires(child, self) apply_requires(child, self)
#needed to ?
if child not in self._cfgimpl_descr._children[1]: if child not in self._cfgimpl_descr._children[1]:
raise AttributeError(_('unknown option {0}').format(name)) raise AttributeError(_('unknown option {0}').format(name))
if setting.has_property('everything_frozen'):
raise ConfigError(_("cannot set a value to the option {0} 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 ConfigError(_('cannot change the value to {0} for '
'option {1} this option is frozen').format(str(value), name))
self.cfgimpl_get_values()[child] = value 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):

View File

@ -33,8 +33,7 @@ class AmbigousOptionError(StandardError):
class ConfigError(StandardError): class ConfigError(StandardError):
"""if modify frozen config """try to change owner for an option without value
or try to change owner for an option without value
or if error in calculation""" or if error in calculation"""
pass pass

View File

@ -211,6 +211,41 @@ class Setting(object):
self.set_properties(properties, opt) self.set_properties(properties, opt)
#____________________________________________________________ #____________________________________________________________
def validate_properties(self, opt_or_descr, is_descr, is_write,
value=None, force_permissive=False,
force_properties=None):
properties = set(self.get_properties(opt_or_descr))
#remove this properties, those properties are validate in after
properties = properties - set(['mandatory', 'frozen'])
set_properties = self.get_properties()
if force_properties is not None:
set_properties.extend(force_properties)
set_properties = set(set_properties)
properties = properties & set_properties
if force_permissive is True or self.has_property('permissive', is_apply_req=False):
properties = properties - set(self.get_permissive())
properties = properties - set(self.get_permissive(opt_or_descr))
properties = list(properties)
raise_text = _("trying to access"
" to an option named: {0} with properties"
" {1}")
if not is_descr:
if self.context.cfgimpl_get_values().is_mandatory_err(opt_or_descr,
value,
force_properties=force_properties):
properties.append('mandatory')
if is_write and (self.has_property('everything_frozen') or (
self.has_property('frozen') and
self.has_property('frozen', opt_or_descr,
is_apply_req=False))):
properties.append('frozen')
raise_text = _('cannot change the value to {0} for '
'option {1} this option is frozen')
if properties != []:
raise PropertiesOptionError(raise_text.format(opt_or_descr._name,
str(properties)),
properties)
def get_permissive(self, opt=None): def get_permissive(self, opt=None):
return self.permissives.get(opt, []) return self.permissives.get(opt, [])

View File

@ -107,10 +107,11 @@ class Values(object):
def __getitem__(self, opt): def __getitem__(self, opt):
return self._getitem(opt) return self._getitem(opt)
def _getitem(self, opt, validate=True): def _getitem(self, opt, validate=True, force_permissive=False,
force_properties=None):
# options with callbacks # options with callbacks
value = self._get_value(opt)
setting = self.context.cfgimpl_get_settings() setting = self.context.cfgimpl_get_settings()
value = self._get_value(opt)
is_frozen = setting.has_property('frozen', opt, False) is_frozen = setting.has_property('frozen', opt, False)
if opt.has_callback(): if opt.has_callback():
#if value is set and : #if value is set and :
@ -137,11 +138,23 @@ class Values(object):
if self.is_default_owner(opt) and \ if self.is_default_owner(opt) and \
setting.has_property('force_store_value', opt, False): setting.has_property('force_store_value', opt, False):
self.setitem(opt, value, validate=validate) self.setitem(opt, value, validate=validate)
setting.validate_properties(opt, False, False, value=value,
force_permissive=force_permissive,
force_properties=force_properties)
return value return value
def __setitem__(self, opt, value): def __setitem__(self, opt, value):
#valid config
#FIXME:
force_permissive = False
force_properties = None
setting = self.context.cfgimpl_get_settings()
setting.validate_properties(opt, False, True,
value=value, force_permissive=force_permissive,
force_properties=force_properties)
#valid opt
if not opt.validate(value, self.context, if not opt.validate(value, self.context,
self.context.cfgimpl_get_settings().has_property('validator')): setting.has_property('validator')):
raise ValueError(_('invalid value {}' raise ValueError(_('invalid value {}'
' for option {}').format(value, opt._name)) ' for option {}').format(value, opt._name))
if opt.is_multi(): if opt.is_multi():
@ -227,7 +240,11 @@ class Multi(list):
" which is a slave").format(self.opt._name)) " which is a slave").format(self.opt._name))
elif self.opt.get_multitype() == multitypes.master: elif self.opt.get_multitype() == multitypes.master:
for slave in self.opt.get_master_slaves(): for slave in self.opt.get_master_slaves():
self.context.cfgimpl_get_values()[slave].append(slave.getdefault_multi(), force=True) self.context.cfgimpl_get_values()[slave].append(
slave.getdefault_multi(), force=True)
self.context.cfgimpl_get_settings().validate_properties(self.opt,
False, True,
value=value)
self._validate(value) self._validate(value)
self.context.cfgimpl_get_values().setitem(self.opt, self) self.context.cfgimpl_get_values().setitem(self.opt, self)
super(Multi, self).append(value) super(Multi, self).append(value)