add global 'empty' property, this property raise mandatory PropertiesOptionError if multi or master have empty value

This commit is contained in:
Emmanuel Garette 2015-07-26 18:55:21 +02:00
parent 1da83edfba
commit 8e7a32de08
7 changed files with 145 additions and 22 deletions

View File

@ -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.

View File

@ -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']

View File

@ -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")

View File

@ -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):

View File

@ -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:

View File

@ -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

View File

@ -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"