add global 'empty' property, this property raise mandatory PropertiesOptionError if multi or master have empty value
This commit is contained in:
parent
1da83edfba
commit
8e7a32de08
|
@ -1,3 +1,7 @@
|
||||||
|
Sun Jul 26 19:09:29 2015 +0200 Emmanuel Garette <egarette@cadoles.com>
|
||||||
|
* add global 'empty' property, this property raise mandatory
|
||||||
|
PropertiesOptionError if multi or master have empty value
|
||||||
|
|
||||||
Fri Jul 24 18:03:59 2015 +0200 Emmanuel Garette <egarette@cadoles.com>
|
Fri Jul 24 18:03:59 2015 +0200 Emmanuel Garette <egarette@cadoles.com>
|
||||||
* add duplicate option to Config, to generate new Config with same
|
* add duplicate option to Config, to generate new Config with same
|
||||||
value, properties, Option. Option are not duplication.
|
value, properties, Option. Option are not duplication.
|
||||||
|
|
|
@ -1,12 +1,13 @@
|
||||||
|
# coding: utf-8
|
||||||
from autopath import do_autopath
|
from autopath import do_autopath
|
||||||
do_autopath()
|
do_autopath()
|
||||||
|
|
||||||
from time import sleep
|
from time import sleep
|
||||||
|
|
||||||
#from py.test import raises
|
from py.test import raises
|
||||||
from tiramisu.config import Config
|
from tiramisu.config import Config
|
||||||
from tiramisu.option import StrOption, UnicodeOption, OptionDescription
|
from tiramisu.option import StrOption, UnicodeOption, OptionDescription
|
||||||
from tiramisu.error import PropertiesOptionError
|
from tiramisu.error import PropertiesOptionError
|
||||||
|
from tiramisu.setting import groups
|
||||||
|
|
||||||
|
|
||||||
def make_description():
|
def make_description():
|
||||||
|
@ -316,3 +317,87 @@ def test_mandatory_warnings_frozen():
|
||||||
config.read_only()
|
config.read_only()
|
||||||
assert config.cfgimpl_get_values().mandatory_warnings() == ['str', 'str1', 'unicode2', 'str3']
|
assert config.cfgimpl_get_values().mandatory_warnings() == ['str', 'str1', 'unicode2', 'str3']
|
||||||
sleep(.1)
|
sleep(.1)
|
||||||
|
|
||||||
|
|
||||||
|
def test_mandatory_master():
|
||||||
|
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True,
|
||||||
|
properties=('mandatory', ))
|
||||||
|
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau",
|
||||||
|
multi=True)
|
||||||
|
interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||||
|
interface1.impl_set_group_type(groups.master)
|
||||||
|
o = OptionDescription('o', '', [interface1])
|
||||||
|
config = Config(o)
|
||||||
|
config.read_only()
|
||||||
|
raises(PropertiesOptionError, 'config.ip_admin_eth0.ip_admin_eth0')
|
||||||
|
raises(PropertiesOptionError, 'config.ip_admin_eth0.netmask_admin_eth0')
|
||||||
|
|
||||||
|
|
||||||
|
def test_mandatory_master_empty():
|
||||||
|
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
|
||||||
|
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau",
|
||||||
|
multi=True)
|
||||||
|
interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||||
|
interface1.impl_set_group_type(groups.master)
|
||||||
|
o = OptionDescription('o', '', [interface1])
|
||||||
|
config = Config(o)
|
||||||
|
config.read_write()
|
||||||
|
assert config.ip_admin_eth0.ip_admin_eth0 == []
|
||||||
|
assert config.ip_admin_eth0.netmask_admin_eth0 == []
|
||||||
|
#
|
||||||
|
config.ip_admin_eth0.ip_admin_eth0.append()
|
||||||
|
assert config.ip_admin_eth0.ip_admin_eth0 == [None]
|
||||||
|
assert config.ip_admin_eth0.netmask_admin_eth0 == [None]
|
||||||
|
config.read_only()
|
||||||
|
raises(PropertiesOptionError, "config.ip_admin_eth0.ip_admin_eth0")
|
||||||
|
raises(PropertiesOptionError, "config.ip_admin_eth0.netmask_admin_eth0")
|
||||||
|
config.read_write()
|
||||||
|
del(config.ip_admin_eth0.ip_admin_eth0)
|
||||||
|
del(config.ip_admin_eth0.netmask_admin_eth0)
|
||||||
|
assert config.ip_admin_eth0.ip_admin_eth0 == []
|
||||||
|
assert config.ip_admin_eth0.netmask_admin_eth0 == []
|
||||||
|
#
|
||||||
|
config.ip_admin_eth0.ip_admin_eth0.append('')
|
||||||
|
assert config.ip_admin_eth0.ip_admin_eth0 == ['']
|
||||||
|
assert config.ip_admin_eth0.netmask_admin_eth0 == [None]
|
||||||
|
config.read_only()
|
||||||
|
raises(PropertiesOptionError, "config.ip_admin_eth0.ip_admin_eth0")
|
||||||
|
raises(PropertiesOptionError, "config.ip_admin_eth0.netmask_admin_eth0")
|
||||||
|
config.read_write()
|
||||||
|
#
|
||||||
|
config.read_write()
|
||||||
|
config.ip_admin_eth0.ip_admin_eth0 = ['ip']
|
||||||
|
config.read_only()
|
||||||
|
assert config.ip_admin_eth0.ip_admin_eth0 == ['ip']
|
||||||
|
assert config.ip_admin_eth0.netmask_admin_eth0 == [None]
|
||||||
|
|
||||||
|
|
||||||
|
def test_mandatory_slave():
|
||||||
|
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
|
||||||
|
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau",
|
||||||
|
multi=True, properties=('mandatory', ))
|
||||||
|
interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||||
|
interface1.impl_set_group_type(groups.master)
|
||||||
|
o = OptionDescription('o', '', [interface1])
|
||||||
|
config = Config(o)
|
||||||
|
config.read_only()
|
||||||
|
assert config.ip_admin_eth0.ip_admin_eth0 == []
|
||||||
|
assert config.ip_admin_eth0.netmask_admin_eth0 == []
|
||||||
|
#
|
||||||
|
config.read_write()
|
||||||
|
config.ip_admin_eth0.ip_admin_eth0.append('ip')
|
||||||
|
config.read_only()
|
||||||
|
assert config.ip_admin_eth0.ip_admin_eth0 == ['ip']
|
||||||
|
raises(PropertiesOptionError, 'config.ip_admin_eth0.netmask_admin_eth0')
|
||||||
|
#
|
||||||
|
config.read_write()
|
||||||
|
config.ip_admin_eth0.netmask_admin_eth0 = ['']
|
||||||
|
config.read_only()
|
||||||
|
assert config.ip_admin_eth0.ip_admin_eth0 == ['ip']
|
||||||
|
raises(PropertiesOptionError, 'config.ip_admin_eth0.netmask_admin_eth0')
|
||||||
|
#
|
||||||
|
config.read_write()
|
||||||
|
config.ip_admin_eth0.netmask_admin_eth0 = ['ip']
|
||||||
|
config.read_only()
|
||||||
|
assert config.ip_admin_eth0.ip_admin_eth0 == ['ip']
|
||||||
|
assert config.ip_admin_eth0.netmask_admin_eth0 == ['ip']
|
||||||
|
|
|
@ -3,9 +3,9 @@ from autopath import do_autopath
|
||||||
do_autopath()
|
do_autopath()
|
||||||
|
|
||||||
from tiramisu.value import Multi
|
from tiramisu.value import Multi
|
||||||
from tiramisu.option import IntOption, OptionDescription
|
from tiramisu.option import IntOption, StrOption, OptionDescription
|
||||||
from tiramisu.config import Config
|
from tiramisu.config import Config
|
||||||
from tiramisu.error import ConfigError
|
from tiramisu.error import ConfigError, PropertiesOptionError
|
||||||
|
|
||||||
import weakref
|
import weakref
|
||||||
from py.test import raises
|
from py.test import raises
|
||||||
|
@ -21,3 +21,21 @@ def test_multi():
|
||||||
assert c is multi._getcontext()
|
assert c is multi._getcontext()
|
||||||
del(c)
|
del(c)
|
||||||
raises(ConfigError, "multi._getcontext()")
|
raises(ConfigError, "multi._getcontext()")
|
||||||
|
|
||||||
|
|
||||||
|
def test_multi_none():
|
||||||
|
s = StrOption('str', '', multi=True)
|
||||||
|
o = OptionDescription('od', '', [s])
|
||||||
|
c = Config(o)
|
||||||
|
c.read_only()
|
||||||
|
assert c.str == []
|
||||||
|
c.read_write()
|
||||||
|
c.str.append(None)
|
||||||
|
assert c.str == [None]
|
||||||
|
c.read_only()
|
||||||
|
raises(PropertiesOptionError, "c.str")
|
||||||
|
c.read_write()
|
||||||
|
c.str = ['']
|
||||||
|
assert c.str == ['']
|
||||||
|
c.read_only()
|
||||||
|
raises(PropertiesOptionError, "c.str")
|
||||||
|
|
|
@ -99,7 +99,7 @@ class Base(StorageBase):
|
||||||
def __init__(self, name, doc, default=None, default_multi=None,
|
def __init__(self, name, doc, default=None, default_multi=None,
|
||||||
requires=None, multi=False, callback=None,
|
requires=None, multi=False, callback=None,
|
||||||
callback_params=None, validator=None, validator_params=None,
|
callback_params=None, validator=None, validator_params=None,
|
||||||
properties=None, warnings_only=False, extra=None, allow_empty_list=False):
|
properties=None, warnings_only=False, extra=None, allow_empty_list=undefined):
|
||||||
if not valid_name(name): # pragma: optional cover
|
if not valid_name(name): # pragma: optional cover
|
||||||
raise ValueError(_("invalid name: {0} for option").format(name))
|
raise ValueError(_("invalid name: {0} for option").format(name))
|
||||||
if requires is not None:
|
if requires is not None:
|
||||||
|
@ -900,7 +900,7 @@ class SymLinkOption(OnlyOption):
|
||||||
'for symlink {0}').format(name))
|
'for symlink {0}').format(name))
|
||||||
super(Base, self).__init__(name, undefined, undefined, undefined,
|
super(Base, self).__init__(name, undefined, undefined, undefined,
|
||||||
undefined, undefined, undefined, undefined,
|
undefined, undefined, undefined, undefined,
|
||||||
False, opt)
|
undefined, opt)
|
||||||
self.commit()
|
self.commit()
|
||||||
|
|
||||||
def __getattr__(self, name, context=undefined):
|
def __getattr__(self, name, context=undefined):
|
||||||
|
|
|
@ -75,6 +75,9 @@ everything_frozen
|
||||||
whole option in config are frozen (even if option have not frozen
|
whole option in config are frozen (even if option have not frozen
|
||||||
property)
|
property)
|
||||||
|
|
||||||
|
empty
|
||||||
|
raise mandatory PropertiesOptionError if multi or master have empty value
|
||||||
|
|
||||||
validator
|
validator
|
||||||
launch validator set by user in option (this property has no effect
|
launch validator set by user in option (this property has no effect
|
||||||
for internal validator)
|
for internal validator)
|
||||||
|
@ -97,10 +100,10 @@ read_write
|
||||||
you can set all variables not frozen
|
you can set all variables not frozen
|
||||||
"""
|
"""
|
||||||
ro_append = set(['frozen', 'disabled', 'validator', 'everything_frozen',
|
ro_append = set(['frozen', 'disabled', 'validator', 'everything_frozen',
|
||||||
'mandatory'])
|
'mandatory', 'empty'])
|
||||||
ro_remove = set(['permissive', 'hidden'])
|
ro_remove = set(['permissive', 'hidden'])
|
||||||
rw_append = set(['frozen', 'disabled', 'validator', 'hidden'])
|
rw_append = set(['frozen', 'disabled', 'validator', 'hidden'])
|
||||||
rw_remove = set(['permissive', 'everything_frozen', 'mandatory'])
|
rw_remove = set(['permissive', 'everything_frozen', 'mandatory', 'empty'])
|
||||||
|
|
||||||
|
|
||||||
forbidden_set_properties = set(['force_store_value'])
|
forbidden_set_properties = set(['force_store_value'])
|
||||||
|
@ -468,8 +471,13 @@ class Settings(object):
|
||||||
else:
|
else:
|
||||||
if 'mandatory' in properties and \
|
if 'mandatory' in properties and \
|
||||||
not self._getcontext().cfgimpl_get_values()._isempty(
|
not self._getcontext().cfgimpl_get_values()._isempty(
|
||||||
opt_or_descr, value, opt_or_descr.impl_allow_empty_list()):
|
opt_or_descr, value):
|
||||||
properties.remove('mandatory')
|
properties.remove('mandatory')
|
||||||
|
elif not is_write and 'empty' in forced_properties and \
|
||||||
|
not opt_or_descr.impl_is_master_slaves('slave') and \
|
||||||
|
self._getcontext().cfgimpl_get_values()._isempty(
|
||||||
|
opt_or_descr, value, force_allow_empty_list=True):
|
||||||
|
properties.add('mandatory')
|
||||||
if is_write and 'everything_frozen' in forced_properties:
|
if is_write and 'everything_frozen' in forced_properties:
|
||||||
properties.add('frozen')
|
properties.add('frozen')
|
||||||
elif 'frozen' in properties and not is_write:
|
elif 'frozen' in properties and not is_write:
|
||||||
|
|
|
@ -79,7 +79,7 @@ class StorageBase(object):
|
||||||
self._properties = properties
|
self._properties = properties
|
||||||
if opt is not undefined:
|
if opt is not undefined:
|
||||||
self._opt = opt
|
self._opt = opt
|
||||||
if allow_empty_list is not False:
|
if allow_empty_list is not undefined:
|
||||||
self._allow_empty_list = allow_empty_list
|
self._allow_empty_list = allow_empty_list
|
||||||
|
|
||||||
def _set_default_values(self, default, default_multi):
|
def _set_default_values(self, default, default_multi):
|
||||||
|
@ -302,8 +302,7 @@ class StorageBase(object):
|
||||||
try:
|
try:
|
||||||
return self._allow_empty_list
|
return self._allow_empty_list
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
return False
|
return undefined
|
||||||
|
|
||||||
|
|
||||||
def _get_extra(self, key):
|
def _get_extra(self, key):
|
||||||
extra = self._extra
|
extra = self._extra
|
||||||
|
|
|
@ -175,18 +175,27 @@ class Values(object):
|
||||||
if hasvalue:
|
if hasvalue:
|
||||||
self._p_.resetvalue(path)
|
self._p_.resetvalue(path)
|
||||||
|
|
||||||
def _isempty(self, opt, value, allow_empty_list):
|
def _isempty(self, opt, value, force_allow_empty_list=False):
|
||||||
"convenience method to know if an option is empty"
|
"convenience method to know if an option is empty"
|
||||||
empty = opt._empty
|
if value is undefined:
|
||||||
if value is not undefined:
|
return False
|
||||||
empty_not_multi = not opt.impl_is_multi() and (value is None or
|
|
||||||
value == empty)
|
|
||||||
empty_multi = opt.impl_is_multi() and ((not allow_empty_list and value == []) or
|
|
||||||
None in value or
|
|
||||||
empty in value)
|
|
||||||
else:
|
else:
|
||||||
empty_multi = empty_not_multi = False
|
empty = opt._empty
|
||||||
return empty_not_multi or empty_multi
|
if opt.impl_is_multi():
|
||||||
|
if force_allow_empty_list:
|
||||||
|
allow_empty_list = True
|
||||||
|
else:
|
||||||
|
allow_empty_list = opt.impl_allow_empty_list()
|
||||||
|
if allow_empty_list is undefined:
|
||||||
|
if opt.impl_is_master_slaves('slave'):
|
||||||
|
allow_empty_list = True
|
||||||
|
else:
|
||||||
|
allow_empty_list = False
|
||||||
|
isempty = (not allow_empty_list and value == []) or \
|
||||||
|
None in value or empty in value
|
||||||
|
else:
|
||||||
|
isempty = value is None or value == empty
|
||||||
|
return isempty
|
||||||
|
|
||||||
def __getitem__(self, opt):
|
def __getitem__(self, opt):
|
||||||
"enables us to use the pythonic dictionary-like access to values"
|
"enables us to use the pythonic dictionary-like access to values"
|
||||||
|
|
Loading…
Reference in New Issue