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
7 changed files with 145 additions and 22 deletions
|
@ -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>
|
||||
* add duplicate option to Config, to generate new Config with same
|
||||
value, properties, Option. Option are not duplication.
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
# coding: utf-8
|
||||
from autopath import do_autopath
|
||||
do_autopath()
|
||||
|
||||
from time import sleep
|
||||
|
||||
#from py.test import raises
|
||||
from py.test import raises
|
||||
from tiramisu.config import Config
|
||||
from tiramisu.option import StrOption, UnicodeOption, OptionDescription
|
||||
from tiramisu.error import PropertiesOptionError
|
||||
from tiramisu.setting import groups
|
||||
|
||||
|
||||
def make_description():
|
||||
|
@ -316,3 +317,87 @@ def test_mandatory_warnings_frozen():
|
|||
config.read_only()
|
||||
assert config.cfgimpl_get_values().mandatory_warnings() == ['str', 'str1', 'unicode2', 'str3']
|
||||
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()
|
||||
|
||||
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.error import ConfigError
|
||||
from tiramisu.error import ConfigError, PropertiesOptionError
|
||||
|
||||
import weakref
|
||||
from py.test import raises
|
||||
|
@ -21,3 +21,21 @@ def test_multi():
|
|||
assert c is multi._getcontext()
|
||||
del(c)
|
||||
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,
|
||||
requires=None, multi=False, callback=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
|
||||
raise ValueError(_("invalid name: {0} for option").format(name))
|
||||
if requires is not None:
|
||||
|
@ -900,7 +900,7 @@ class SymLinkOption(OnlyOption):
|
|||
'for symlink {0}').format(name))
|
||||
super(Base, self).__init__(name, undefined, undefined, undefined,
|
||||
undefined, undefined, undefined, undefined,
|
||||
False, opt)
|
||||
undefined, opt)
|
||||
self.commit()
|
||||
|
||||
def __getattr__(self, name, context=undefined):
|
||||
|
|
|
@ -75,6 +75,9 @@ everything_frozen
|
|||
whole option in config are frozen (even if option have not frozen
|
||||
property)
|
||||
|
||||
empty
|
||||
raise mandatory PropertiesOptionError if multi or master have empty value
|
||||
|
||||
validator
|
||||
launch validator set by user in option (this property has no effect
|
||||
for internal validator)
|
||||
|
@ -97,10 +100,10 @@ read_write
|
|||
you can set all variables not frozen
|
||||
"""
|
||||
ro_append = set(['frozen', 'disabled', 'validator', 'everything_frozen',
|
||||
'mandatory'])
|
||||
'mandatory', 'empty'])
|
||||
ro_remove = set(['permissive', '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'])
|
||||
|
@ -468,8 +471,13 @@ class Settings(object):
|
|||
else:
|
||||
if 'mandatory' in properties and \
|
||||
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')
|
||||
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:
|
||||
properties.add('frozen')
|
||||
elif 'frozen' in properties and not is_write:
|
||||
|
|
|
@ -79,7 +79,7 @@ class StorageBase(object):
|
|||
self._properties = properties
|
||||
if opt is not undefined:
|
||||
self._opt = opt
|
||||
if allow_empty_list is not False:
|
||||
if allow_empty_list is not undefined:
|
||||
self._allow_empty_list = allow_empty_list
|
||||
|
||||
def _set_default_values(self, default, default_multi):
|
||||
|
@ -302,8 +302,7 @@ class StorageBase(object):
|
|||
try:
|
||||
return self._allow_empty_list
|
||||
except AttributeError:
|
||||
return False
|
||||
|
||||
return undefined
|
||||
|
||||
def _get_extra(self, key):
|
||||
extra = self._extra
|
||||
|
|
|
@ -175,18 +175,27 @@ class Values(object):
|
|||
if hasvalue:
|
||||
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"
|
||||
empty = opt._empty
|
||||
if value is not undefined:
|
||||
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)
|
||||
if value is undefined:
|
||||
return False
|
||||
else:
|
||||
empty_multi = empty_not_multi = False
|
||||
return empty_not_multi or empty_multi
|
||||
empty = opt._empty
|
||||
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):
|
||||
"enables us to use the pythonic dictionary-like access to values"
|
||||
|
|
Loading…
Reference in a new issue