Merge branch 'master' into orm

Conflicts:
	tiramisu/config.py
	tiramisu/option.py
This commit is contained in:
Emmanuel Garette 2014-02-04 21:48:20 +01:00
commit 98bd35ad36
8 changed files with 92 additions and 32 deletions

View File

@ -4,7 +4,8 @@ from py.test import raises
from tiramisu.config import Config from tiramisu.config import Config
from tiramisu.option import IntOption, FloatOption, StrOption, ChoiceOption, \ from tiramisu.option import IntOption, FloatOption, StrOption, ChoiceOption, \
BoolOption, FilenameOption, OptionDescription BoolOption, FilenameOption, UnicodeOption, SymLinkOption, IPOption, \
PortOption, OptionDescription
def make_description(): def make_description():
@ -150,6 +151,7 @@ def test_find_in_config():
# not OptionDescription # not OptionDescription
raises(AttributeError, "conf.find_first(byname='gc')") raises(AttributeError, "conf.find_first(byname='gc')")
raises(AttributeError, "conf.gc.find_first(byname='gc2')") raises(AttributeError, "conf.gc.find_first(byname='gc2')")
raises(ValueError, "conf.find(byname='bool', type_='unknown')")
def test_find_multi(): def test_find_multi():
@ -208,3 +210,18 @@ def test_iter_all_prop():
config = Config(descr) config = Config(descr)
config.read_only() config.read_only()
assert list(config.iter_all()) == [('string2', 'string2')] assert list(config.iter_all()) == [('string2', 'string2')]
def test_invalid_option():
raises(TypeError, "ChoiceOption('a', '', [1, 2])")
raises(TypeError, "ChoiceOption('a', '', 1)")
raises(TypeError, "ChoiceOption('a', '', (1,), open_values='string')")
raises(ValueError, "ChoiceOption('a', '', (1,), 3)")
raises(ValueError, "FloatOption('a', '', 'string')")
raises(ValueError, "UnicodeOption('a', '', 1)")
raises(ValueError, "SymLinkOption('a', 'string')")
raises(ValueError, "IPOption('a', '', 1)")
raises(ValueError, "IPOption('a', '', 'string')")
raises(ValueError, "PortOption('a', '', 'string')")
raises(ValueError, "PortOption('a', '', '11:12:13', allow_range=True)")
raises(ValueError, "PortOption('a', '', 11111111111111111111)")

View File

@ -5,7 +5,7 @@ from py.test import raises
from tiramisu.setting import owners from tiramisu.setting import owners
from tiramisu.config import Config, GroupConfig, MetaConfig from tiramisu.config import Config, GroupConfig, MetaConfig
from tiramisu.option import IntOption, OptionDescription from tiramisu.option import IntOption, OptionDescription
from tiramisu.error import ConfigError from tiramisu.error import ConfigError, PropertiesOptionError
owners.addowner('meta') owners.addowner('meta')
@ -15,10 +15,14 @@ def make_description():
i2 = IntOption('i2', '', default=1) i2 = IntOption('i2', '', default=1)
i3 = IntOption('i3', '') i3 = IntOption('i3', '')
i4 = IntOption('i4', '', default=2) i4 = IntOption('i4', '', default=2)
od1 = OptionDescription('od1', '', [i1, i2, i3, i4]) i5 = IntOption('i5', '', default=[2], multi=True)
i6 = IntOption('i6', '', properties=('disabled',))
od1 = OptionDescription('od1', '', [i1, i2, i3, i4, i5, i6])
od2 = OptionDescription('od2', '', [od1]) od2 = OptionDescription('od2', '', [od1])
conf1 = Config(od2) conf1 = Config(od2)
conf2 = Config(od2) conf2 = Config(od2)
conf1.read_write()
conf2.read_write()
meta = MetaConfig([conf1, conf2]) meta = MetaConfig([conf1, conf2])
meta.cfgimpl_get_settings().setowner(owners.meta) meta.cfgimpl_get_settings().setowner(owners.meta)
return meta return meta
@ -29,7 +33,7 @@ def make_description():
#FIXME serialization #FIXME serialization
def test_none(): def test_none():
meta = make_description() meta = make_description()
conf1, conf2 = meta._impl_children conf1, conf2 = meta.cfgimpl_get_children()
assert conf1.od1.i3 is conf2.od1.i3 is None assert conf1.od1.i3 is conf2.od1.i3 is None
assert conf1.getowner(conf1.unwrap_from_path('od1.i3')) is conf2.getowner(conf2.unwrap_from_path('od1.i3')) is owners.default assert conf1.getowner(conf1.unwrap_from_path('od1.i3')) is conf2.getowner(conf2.unwrap_from_path('od1.i3')) is owners.default
meta.od1.i3 = 3 meta.od1.i3 = 3
@ -58,7 +62,7 @@ def test_none():
def test_default(): def test_default():
meta = make_description() meta = make_description()
conf1, conf2 = meta._impl_children conf1, conf2 = meta.cfgimpl_get_children()
assert conf1.od1.i2 == conf2.od1.i2 == 1 assert conf1.od1.i2 == conf2.od1.i2 == 1
assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default
meta.od1.i2 = 3 meta.od1.i2 = 3
@ -87,7 +91,7 @@ def test_default():
def test_contexts(): def test_contexts():
meta = make_description() meta = make_description()
conf1, conf2 = meta._impl_children conf1, conf2 = meta.cfgimpl_get_children()
assert conf1.od1.i2 == conf2.od1.i2 == 1 assert conf1.od1.i2 == conf2.od1.i2 == 1
assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default
meta.setattrs('od1.i2', 6) meta.setattrs('od1.i2', 6)
@ -101,14 +105,15 @@ def test_find():
i2 = meta.unwrap_from_path('od1.i2') i2 = meta.unwrap_from_path('od1.i2')
assert [i2] == meta.find(byname='i2') assert [i2] == meta.find(byname='i2')
assert i2 == meta.find_first(byname='i2') assert i2 == meta.find_first(byname='i2')
assert meta.make_dict() == {'od1.i4': 2, 'od1.i1': None, 'od1.i3': None, 'od1.i2': 1} assert meta.make_dict() == {'od1.i4': 2, 'od1.i1': None, 'od1.i3': None,
'od1.i2': 1, 'od1.i5': [2], 'od1.i6': None}
def test_meta_meta(): def test_meta_meta():
meta1 = make_description() meta1 = make_description()
meta2 = MetaConfig([meta1]) meta2 = MetaConfig([meta1])
meta2.cfgimpl_get_settings().setowner(owners.meta) meta2.cfgimpl_get_settings().setowner(owners.meta)
conf1, conf2 = meta1._impl_children conf1, conf2 = meta1.cfgimpl_get_children()
assert conf1.od1.i2 == conf2.od1.i2 == 1 assert conf1.od1.i2 == conf2.od1.i2 == 1
assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default assert conf1.getowner(conf1.unwrap_from_path('od1.i2')) is conf2.getowner(conf2.unwrap_from_path('od1.i2')) is owners.default
meta2.od1.i2 = 3 meta2.od1.i2 = 3
@ -142,15 +147,21 @@ def test_meta_meta_set():
meta1 = make_description() meta1 = make_description()
meta2 = MetaConfig([meta1]) meta2 = MetaConfig([meta1])
meta2.cfgimpl_get_settings().setowner(owners.meta) meta2.cfgimpl_get_settings().setowner(owners.meta)
conf1, conf2 = meta1._impl_children conf1, conf2 = meta1.cfgimpl_get_children()
meta2.setattrs('od1.i1', 7) meta2.setattrs('od1.i1', 7)
#PropertiesOptionError
meta2.setattrs('od1.i6', 7)
assert conf1.od1.i1 == conf2.od1.i1 == 7 assert conf1.od1.i1 == conf2.od1.i1 == 7
assert conf1.getowner(conf1.unwrap_from_path('od1.i1')) is conf2.getowner(conf2.unwrap_from_path('od1.i1')) is owners.user assert conf1.getowner(conf1.unwrap_from_path('od1.i1')) is conf2.getowner(conf2.unwrap_from_path('od1.i1')) is owners.user
assert [conf1, conf2] == meta2.find_firsts(byname='i1', byvalue=7) assert [conf1, conf2] == meta2.find_firsts(byname='i1', byvalue=7)
conf1.od1.i1 = 8 conf1.od1.i1 = 8
assert [conf1, conf2] == meta2.find_firsts(byname='i1')
assert [conf2] == meta2.find_firsts(byname='i1', byvalue=7) assert [conf2] == meta2.find_firsts(byname='i1', byvalue=7)
assert [conf1] == meta2.find_firsts(byname='i1', byvalue=8) assert [conf1] == meta2.find_firsts(byname='i1', byvalue=8)
assert [conf1, conf2] == meta2.find_firsts(byname='i5', byvalue=2)
raises(AttributeError, "meta2.find_firsts(byname='i1', byvalue=10)") raises(AttributeError, "meta2.find_firsts(byname='i1', byvalue=10)")
raises(AttributeError, "meta2.find_firsts(byname='not', byvalue=10)")
raises(AttributeError, "meta2.find_firsts(byname='i6')")
def test_not_meta(): def test_not_meta():
@ -159,9 +170,10 @@ def test_not_meta():
od2 = OptionDescription('od2', '', [od1]) od2 = OptionDescription('od2', '', [od1])
conf1 = Config(od2) conf1 = Config(od2)
conf2 = Config(od2) conf2 = Config(od2)
raises(ValueError, "GroupConfig(conf1)")
meta = GroupConfig([conf1, conf2]) meta = GroupConfig([conf1, conf2])
raises(ConfigError, 'meta.od1.i1') raises(ConfigError, 'meta.od1.i1')
conf1, conf2 = meta._impl_children conf1, conf2 = meta.cfgimpl_get_children()
meta.setattrs('od1.i1', 7) meta.setattrs('od1.i1', 7)
assert conf1.od1.i1 == conf2.od1.i1 == 7 assert conf1.od1.i1 == conf2.od1.i1 == 7
assert conf1.getowner(conf1.unwrap_from_path('od1.i1')) is conf2.getowner(conf2.unwrap_from_path('od1.i1')) is owners.user assert conf1.getowner(conf1.unwrap_from_path('od1.i1')) is conf2.getowner(conf2.unwrap_from_path('od1.i1')) is owners.user

View File

@ -36,6 +36,7 @@ def test_default_owner():
cfg = Config(descr) cfg = Config(descr)
assert cfg.dummy is False assert cfg.dummy is False
assert cfg.getowner(gcdummy) == 'default' assert cfg.getowner(gcdummy) == 'default'
raises(TypeError, "cfg.getowner('gcdummy')")
cfg.dummy = True cfg.dummy = True
assert cfg.getowner(gcdummy) == owners.user assert cfg.getowner(gcdummy) == owners.user

View File

@ -24,6 +24,28 @@ def test_requires():
except PropertiesOptionError as err: except PropertiesOptionError as err:
props = err.proptype props = err.proptype
assert props == ['disabled'] assert props == ['disabled']
c.activate_service = True
c.ip_address_service
def test_requires_with_requires():
a = BoolOption('activate_service', '', True)
b = IPOption('ip_address_service', '',
requires=[{'option': a, 'expected': False, 'action': 'disabled'}])
od = OptionDescription('service', '', [a, b])
c = Config(od)
c.read_write()
c.cfgimpl_get_settings()[b].append('test')
c.ip_address_service
c.activate_service = False
props = []
try:
c.ip_address_service
except PropertiesOptionError as err:
props = err.proptype
assert props == ['disabled']
c.activate_service = True
c.ip_address_service
def test_requires_invalid(): def test_requires_invalid():

View File

@ -434,12 +434,9 @@ class SubConfig(object):
def _make_sub_dict(self, opt, path, pathsvalues, _currpath, flatten): def _make_sub_dict(self, opt, path, pathsvalues, _currpath, flatten):
if isinstance(opt, OptionDescription): if isinstance(opt, OptionDescription):
try: pathsvalues += getattr(self, path).make_dict(flatten,
pathsvalues += getattr(self, path).make_dict(flatten, _currpath +
_currpath + path.split('.'))
path.split('.'))
except PropertiesOptionError:
pass # this just a hidden or disabled option
else: else:
try: try:
value = self._getattr(opt.impl_getname()) value = self._getattr(opt.impl_getname())

View File

@ -715,7 +715,7 @@ class ChoiceOption(Option):
return self._choice_open_values return self._choice_open_values
def _validate(self, value): def _validate(self, value):
if not self._choice_open_values and not value in self._choice_values: if not self.impl_is_openvalues() and not value in self.impl_get_values():
raise ValueError(_('value {0} is not permitted, ' raise ValueError(_('value {0} is not permitted, '
'only {1} is allowed' 'only {1} is allowed'
'').format(value, self._choice_values)) '').format(value, self._choice_values))
@ -832,9 +832,13 @@ class IPOption(Option):
def _validate(self, value): def _validate(self, value):
# sometimes an ip term starts with a zero # sometimes an ip term starts with a zero
# but this does not fit in some case, for example bind does not like it # but this does not fit in some case, for example bind does not like it
for val in value.split('.'): try:
if val.startswith("0") and len(val) > 1: for val in value.split('.'):
raise ValueError(_('invalid IP')) if val.startswith("0") and len(val) > 1:
raise ValueError(_('invalid IP'))
except AttributeError:
#if integer for example
raise ValueError(_('invalid IP'))
# 'standard' validation # 'standard' validation
try: try:
IP('{0}/32'.format(value)) IP('{0}/32'.format(value))
@ -905,18 +909,23 @@ class PortOption(Option):
if self._extra['_allow_range'] and ":" in str(value): if self._extra['_allow_range'] and ":" in str(value):
value = str(value).split(':') value = str(value).split(':')
if len(value) != 2: if len(value) != 2:
raise ValueError('invalid part, range must have two values ' raise ValueError(_('invalid part, range must have two values '
'only') 'only'))
if not value[0] < value[1]: if not value[0] < value[1]:
raise ValueError('invalid port, first port in range must be' raise ValueError(_('invalid port, first port in range must be'
' smaller than the second one') ' smaller than the second one'))
else: else:
value = [value] value = [value]
for val in value: for val in value:
if not self._extra['_min_value'] <= int(val) <= self._extra['_max_value']: try:
raise ValueError('invalid port, must be an between {0} and {1}' if not self._extra['_min_value'] <= int(val) <= self._extra['_max_value']:
''.format(self._extra['_min_value'], self._extra['_max_value'])) raise ValueError('invalid port, must be an between {0} '
'and {1}'.format(
self._extra['_min_value'],
self._extra['_max_value']))
except ValueError:
raise ValueError(_('invalid port'))
class NetworkOption(Option): class NetworkOption(Option):

View File

@ -372,7 +372,7 @@ class Settings(object):
def _getproperties(self, opt=None, path=None, is_apply_req=True): def _getproperties(self, opt=None, path=None, is_apply_req=True):
if opt is None: if opt is None:
props = self._p_.getproperties(path, default_properties) props = copy(self._p_.getproperties(path, default_properties))
else: else:
if path is None: if path is None:
raise ValueError(_('if opt is not None, path should not be' raise ValueError(_('if opt is not None, path should not be'
@ -383,8 +383,8 @@ class Settings(object):
ntime = int(time()) ntime = int(time())
is_cached, props = self._p_.getcache(path, ntime) is_cached, props = self._p_.getcache(path, ntime)
if is_cached: if is_cached:
return props return copy(props)
props = self._p_.getproperties(path, opt._properties) props = copy(self._p_.getproperties(path, opt._properties))
if is_apply_req: if is_apply_req:
props |= self.apply_requires(opt, path) props |= self.apply_requires(opt, path)
if 'cache' in self: if 'cache' in self:
@ -447,8 +447,8 @@ class Settings(object):
(typically with the `frozen` property) (typically with the `frozen` property)
""" """
# opt properties # opt properties
properties = copy(self._getproperties(opt_or_descr, path)) properties = self._getproperties(opt_or_descr, path)
self_properties = copy(self._getproperties()) self_properties = self._getproperties()
# remove opt permissive # remove opt permissive
# permissive affect option's permission with or without permissive # permissive affect option's permission with or without permissive
# global property # global property

View File

@ -66,6 +66,8 @@ class Values(object):
meta = self._getcontext().cfgimpl_get_meta() meta = self._getcontext().cfgimpl_get_meta()
if meta is not None: if meta is not None:
value = meta.cfgimpl_get_values()[opt] value = meta.cfgimpl_get_values()[opt]
if isinstance(value, Multi):
value = list(value)
else: else:
value = opt.impl_getdefault() value = opt.impl_getdefault()
if opt.impl_is_multi(): if opt.impl_is_multi():