separate value in slave

This commit is contained in:
Emmanuel Garette 2015-11-19 22:25:00 +01:00
parent a248508498
commit 54ca54e505
16 changed files with 409 additions and 416 deletions

View file

@ -10,7 +10,7 @@ Sun Jul 26 19:09:29 2015 +0200 Emmanuel Garette <egarette@cadoles.com>
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 duplicated.
Mon Apr 20 14:44:15 2015 +0200 Emmanuel Garette <egarette@cadoles.com> Mon Apr 20 14:44:15 2015 +0200 Emmanuel Garette <egarette@cadoles.com>
* if option is multi, the properties disallow [None] for a multi but * if option is multi, the properties disallow [None] for a multi but
@ -44,7 +44,7 @@ Sun Dec 7 14:37:32 2014 +0200 Emmanuel Garette <egarette@cadoles.com>
Mon Dec 1 22:58:13 2014 +0200 Emmanuel Garette <egarette@cadoles.com> Mon Dec 1 22:58:13 2014 +0200 Emmanuel Garette <egarette@cadoles.com>
* propertyerror are transitive in consistency, now it's possible to set * propertyerror are transitive in consistency, now it's possible to set
non-transitive consistency non-transitive consistency
* if consistency with multiple option return if transitive * support transitive in consistency with multiple option return
* can reset slave value in all case when deleting master value * can reset slave value in all case when deleting master value
* in_network's consistency now verify that IP is not network or * in_network's consistency now verify that IP is not network or
broadcast's IP + ip_netmask's consistency now verify that IP is not broadcast's IP + ip_netmask's consistency now verify that IP is not
@ -52,11 +52,11 @@ Mon Dec 1 22:58:13 2014 +0200 Emmanuel Garette <egarette@cadoles.com>
Sun Oct 26 08:50:38 2014 +0200 Emmanuel Garette <egarette@cadoles.com> Sun Oct 26 08:50:38 2014 +0200 Emmanuel Garette <egarette@cadoles.com>
* if option is frozen with force_default_on_freeze property, owner * if option is frozen with force_default_on_freeze property, owner
must be 'default' check property when tried to change owner must be 'default', check property when tried to change owner
* bad characters in DomainnameOption could be in warning level * bad characters in DomainnameOption could be in warning level
* frozen with force_default_on_freeze can change owner * frozen with force_default_on_freeze can change owner
* add force_permissive to config __iter__ * add force_permissive to config __iter__
* pass force_permissive to slave for a master or to master for a slave * add force_permissive to slave for a master or to master for a slave
* remove mandatory_warnings in config.py * remove mandatory_warnings in config.py
* add force_permissive in mandatory_warnings * add force_permissive in mandatory_warnings
@ -78,13 +78,13 @@ Thu Jun 19 23:20:29 2014 +0200 Emmanuel Garette <egarette@cadoles.com>
Sun Apr 27 10:32:40 2014 +0200 Emmanuel Garette <egarette@cadoles.com> Sun Apr 27 10:32:40 2014 +0200 Emmanuel Garette <egarette@cadoles.com>
* behavior change in ChoiceOption: * behavior change in ChoiceOption:
remove open_values, that no sens (no type validation is possible) if remove open_values, that no sens (we cannot validate type) if
you want something like open_values, please use a typed option and you want something like open_values, please use a typed option and
add impl_(s|g)et_information to add proposed values and use it in your add impl_(s|g)et_information to add proposed values and use it in your
code code
* add dynamic ChoiceOption: * add dynamic ChoiceOption:
we can have dynamic ChoiceOption. Parameter values can be a function we can have dynamic ChoiceOption. Parameter values can be a function
and as callback, we can add values_params and, as callback, we can add values_params
Fri Apr 25 22:57:08 2014 +0200 Emmanuel Garette <egarette@cadoles.com> Fri Apr 25 22:57:08 2014 +0200 Emmanuel Garette <egarette@cadoles.com>
@ -99,8 +99,8 @@ Sat Apr 12 11:37:27 2014 +0200 Emmanuel Garette <egarette@cadoles.com>
* tiramisu/config.py (in cfgimpl_get_home_by_path and getattr) and * tiramisu/config.py (in cfgimpl_get_home_by_path and getattr) and
tiramisu/value.py (in getitem): arity change, remove force_properties tiramisu/value.py (in getitem): arity change, remove force_properties
* tiramisu/option.py: split into tiramisu/option directory * tiramisu/option.py: split into tiramisu/option directory
* tiramisu/option/masterslave.py: master/slaves have no a special * tiramisu/option/masterslave.py: add special object MasterSlaves for
object MasterSlaves for all code related to master/slaves options all code related to master/slaves options
* tiramisu/option/masterslave.py: master and slaves values (length, * tiramisu/option/masterslave.py: check every time master and slaves
consistency, ...) are now check every time values (length, consistency, ...)
* change None to undefined when needed * change None to undefined when needed

View file

@ -904,8 +904,8 @@ def test_masterslaves_dyndescription():
assert cfg.od.stval2.st1val2.st2val2 == [] assert cfg.od.stval2.st1val2.st2val2 == []
assert cfg.getowner(st1val1) == owner assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st1val2) == owners.default assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owner assert cfg.getowner(st2val1, 0) == owner
assert cfg.getowner(st2val2) == owners.default # assert cfg.getowner(st2val2) == owners.default
# #
cfg.od.stval1.st1val1.st1val1.pop(0) cfg.od.stval1.st1val1.st1val1.pop(0)
assert cfg.od.stval1.st1val1.st1val1 == [] assert cfg.od.stval1.st1val1.st1val1 == []
@ -914,18 +914,18 @@ def test_masterslaves_dyndescription():
assert cfg.od.stval2.st1val2.st2val2 == [] assert cfg.od.stval2.st1val2.st2val2 == []
assert cfg.getowner(st1val1) == owner assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st1val2) == owners.default assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owner # assert cfg.getowner(st2val1) == owner
assert cfg.getowner(st2val2) == owners.default # assert cfg.getowner(st2val2) == owners.default
# #
cfg.od.stval1.st1val1.st1val1 = ['yes'] cfg.od.stval1.st1val1.st1val1 = ['yes']
cfg.od.stval1.st1val1.st2val1 = ['yes'] cfg.od.stval1.st1val1.st2val1 = ['yes']
assert cfg.getowner(st1val1) == owner assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st2val1) == owner assert cfg.getowner(st2val1, 0) == owner
del(cfg.od.stval1.st1val1.st2val1) del(cfg.od.stval1.st1val1.st2val1)
assert cfg.getowner(st1val1) == owner assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st1val2) == owners.default assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owners.default # assert cfg.getowner(st2val1) == owners.default
assert cfg.getowner(st2val2) == owners.default # assert cfg.getowner(st2val2) == owners.default
# #
cfg.od.stval1.st1val1.st1val1 = ['yes'] cfg.od.stval1.st1val1.st1val1 = ['yes']
cfg.od.stval1.st1val1.st2val1 = ['yes'] cfg.od.stval1.st1val1.st2val1 = ['yes']
@ -1012,8 +1012,8 @@ def test_masterslaves_submulti_dyndescription():
assert cfg.od.stval2.st1val2.st2val2 == [] assert cfg.od.stval2.st1val2.st2val2 == []
assert cfg.getowner(st1val1) == owner assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st1val2) == owners.default assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owner assert cfg.getowner(st2val1, 0) == owner
assert cfg.getowner(st2val2) == owners.default # assert cfg.getowner(st2val2) == owners.default
def test_masterslaves_consistency_ip_dyndescription(): def test_masterslaves_consistency_ip_dyndescription():
@ -1085,8 +1085,8 @@ def test_masterslaves_callback_dyndescription():
assert cfg.od.stval2.st1val2.st2val2 == [] assert cfg.od.stval2.st1val2.st2val2 == []
assert cfg.getowner(st1val1) == owner assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st1val2) == owners.default assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owner assert cfg.getowner(st2val1, 0) == owner
assert cfg.getowner(st2val2) == owners.default # assert cfg.getowner(st2val2) == owners.default
# #
cfg.od.stval1.st1val1.st1val1.pop(0) cfg.od.stval1.st1val1.st1val1.pop(0)
assert cfg.od.stval1.st1val1.st1val1 == [] assert cfg.od.stval1.st1val1.st1val1 == []
@ -1095,13 +1095,13 @@ def test_masterslaves_callback_dyndescription():
assert cfg.od.stval2.st1val2.st2val2 == [] assert cfg.od.stval2.st1val2.st2val2 == []
assert cfg.getowner(st1val1) == owner assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st1val2) == owners.default assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owner # assert cfg.getowner(st2val1) == owner
assert cfg.getowner(st2val2) == owners.default # assert cfg.getowner(st2val2) == owners.default
# #
cfg.od.stval1.st1val1.st1val1 = ['yes'] cfg.od.stval1.st1val1.st1val1 = ['yes']
cfg.od.stval1.st1val1.st2val1 = ['yes'] cfg.od.stval1.st1val1.st2val1 = ['yes']
assert cfg.getowner(st1val1) == owner assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st2val1) == owner assert cfg.getowner(st2val1, 0) == owner
del(cfg.od.stval1.st1val1.st2val1) del(cfg.od.stval1.st1val1.st2val1)
assert cfg.getowner(st1val1) == owner assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st1val2) == owners.default assert cfg.getowner(st1val2) == owners.default
@ -1159,31 +1159,6 @@ def test_masterslaves_callback_nomulti_dyndescription():
assert cfg.od.stval1.st1val1.st2val1 == ['val'] assert cfg.od.stval1.st1val1.st2val1 == ['val']
def test_masterslaves_callback_multi_dyndescription():
v1 = StrOption('v1', '', multi=True)
st1 = StrOption('st1', "", multi=True)
st2 = StrOption('st2', "", multi=True, callback=return_dynval, callback_params={'': ((v1, False),)})
stm = OptionDescription('st1', '', [st1, st2])
stm.impl_set_group_type(groups.master)
st = DynOptionDescription('st', '', [stm], callback=return_list)
od = OptionDescription('od', '', [st])
od2 = OptionDescription('od', '', [od, v1])
cfg = Config(od2)
assert cfg.od.stval1.st1val1.st1val1 == []
assert cfg.od.stval1.st1val1.st2val1 == []
cfg.od.stval1.st1val1.st1val1.append('yes')
assert cfg.od.stval1.st1val1.st1val1 == ['yes']
assert cfg.od.stval1.st1val1.st2val1 == [None]
cfg.od.stval1.st1val1.st2val1 = ['no']
cfg.v1 = ['no', 'no', 'no']
cfg.od.stval1.st1val1.st1val1.append('yes')
assert cfg.od.stval1.st1val1.st1val1 == ['yes', 'yes']
assert cfg.od.stval1.st1val1.st2val1 == ['no', 'no']
cfg.od.stval1.st1val1.st1val1.pop(1)
assert cfg.od.stval1.st1val1.st1val1 == ['yes']
assert cfg.od.stval1.st1val1.st2val1 == ['no']
def test_masterslaves_callback_samegroup_dyndescription(): def test_masterslaves_callback_samegroup_dyndescription():
st1 = StrOption('st1', "", multi=True) st1 = StrOption('st1', "", multi=True)
st2 = StrOption('st2', "", multi=True) st2 = StrOption('st2', "", multi=True)
@ -1242,11 +1217,11 @@ def test_masterslaves_callback_samegroup_dyndescription():
'od.stval2.st1val2.st2val2': [], 'od.stval2.st1val2.st2val2': [],
'od.stval2.st1val2.st3val2': []} 'od.stval2.st1val2.st3val2': []}
assert cfg.getowner(st1val1) == owner assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st2val1, 0) == owner
assert cfg.getowner(st3val1, 0) == owners.default
assert cfg.getowner(st1val2) == owners.default assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owner #assert cfg.getowner(st2val2) == owners.default
assert cfg.getowner(st2val2) == owners.default #assert cfg.getowner(st3val2) == owners.default
assert cfg.getowner(st3val1) == owners.default
assert cfg.getowner(st3val2) == owners.default
def test_state_config(): def test_state_config():

View file

@ -295,13 +295,13 @@ def test_meta_master_slaves_owners():
assert meta.conf1.getowner(netmask_admin_eth0) == owners.default assert meta.conf1.getowner(netmask_admin_eth0) == owners.default
meta.netmask_admin_eth0 = ['255.255.255.0'] meta.netmask_admin_eth0 = ['255.255.255.0']
assert meta.conf1.getowner(ip_admin_eth0) == owners.meta assert meta.conf1.getowner(ip_admin_eth0) == owners.meta
assert meta.conf1.getowner(netmask_admin_eth0) == owners.meta assert meta.conf1.getowner(netmask_admin_eth0, 0) == owners.meta
meta.netmask_admin_eth0 = ['255.255.0.0'] meta.netmask_admin_eth0 = ['255.255.0.0']
assert meta.conf1.getowner(ip_admin_eth0) == owners.meta assert meta.conf1.getowner(ip_admin_eth0) == owners.meta
assert meta.conf1.getowner(netmask_admin_eth0) == owners.meta assert meta.conf1.getowner(netmask_admin_eth0, 0) == owners.meta
meta.conf1.ip_admin_eth0 = ['192.168.1.1'] meta.conf1.ip_admin_eth0 = ['192.168.1.1']
assert meta.conf1.getowner(ip_admin_eth0) == owners.user assert meta.conf1.getowner(ip_admin_eth0) == owners.user
assert meta.conf1.getowner(netmask_admin_eth0) == owners.default assert meta.conf1.getowner(netmask_admin_eth0, 0) == owners.default
def test_meta_force_default(): def test_meta_force_default():

View file

@ -6,6 +6,7 @@ from tiramisu.value import Multi
from tiramisu.option import IntOption, StrOption, OptionDescription from tiramisu.option import IntOption, StrOption, OptionDescription
from tiramisu.config import Config from tiramisu.config import Config
from tiramisu.error import ConfigError, PropertiesOptionError from tiramisu.error import ConfigError, PropertiesOptionError
from tiramisu.setting import groups
import weakref import weakref
from py.test import raises from py.test import raises

View file

@ -548,33 +548,6 @@ def test_callback_master_and_slaves_slave_cal():
assert cfg.val1.val2 == ['val1', 'val2', 'val'] assert cfg.val1.val2 == ['val1', 'val2', 'val']
def test_callback_master_and_slaves_slave_cal2():
val3 = StrOption('val3', "", ['val', 'val'], multi=True)
val1 = StrOption('val1', "", multi=True, callback=return_value, callback_params={'': ((val3, False),)})
val2 = StrOption('val2', "", ['val2', 'val2'], multi=True)
interface1 = OptionDescription('val1', '', [val1, val2])
interface1.impl_set_group_type(groups.master)
maconfig = OptionDescription('rootconfig', '', [interface1, val3])
cfg = Config(maconfig)
cfg.read_write()
assert cfg.val3 == ['val', 'val']
assert cfg.val1.val1 == ['val', 'val']
assert cfg.val1.val2 == ['val2', 'val2']
cfg.val3.pop(1)
# cannot remove slave's value because master is calculated
# so raise
raises(SlaveError, "cfg.val1.val1")
raises(SlaveError, "cfg.val1.val2")
cfg.val3 = ['val', 'val']
assert cfg.val3 == ['val', 'val']
assert cfg.val1.val1 == ['val', 'val']
assert cfg.val1.val2 == ['val2', 'val2']
raises(SlaveError, "cfg.val1.val1 = ['val']")
assert cfg.val3 == ['val', 'val']
assert cfg.val1.val1 == ['val', 'val']
assert cfg.val1.val2 == ['val2', 'val2']
def test_callback_master_and_slaves_master_disabled(): def test_callback_master_and_slaves_master_disabled():
#properties must be transitive #properties must be transitive
val1 = StrOption('val1', "", multi=True, properties=('disabled',)) val1 = StrOption('val1', "", multi=True, properties=('disabled',))
@ -643,35 +616,16 @@ def test_callback_master_and_slaves_slave_callback_disabled():
cfg = Config(maconfig) cfg = Config(maconfig)
cfg.read_write() cfg.read_write()
assert cfg.val1.val1 == [] assert cfg.val1.val1 == []
raises(ConfigError, "cfg.val1.val2") assert cfg.val1.val2 == []
cfg.val1.val1.append('yes') cfg.val1.val1.append('yes')
assert cfg.val1.val1 == ['yes'] assert cfg.val1.val1 == ['yes']
cfg.cfgimpl_get_settings().remove('disabled') cfg.cfgimpl_get_settings().remove('disabled')
assert cfg.val1.val2 == [None] raises(SlaveError, "cfg.val1.val2")
cfg.val1.val2 = ['no'] cfg.val1.val2 = ['no']
cfg.val1.val1.append('yes1') cfg.val1.val1.append('yes1')
cfg.val1.val2[1] = 'no1'
cfg.cfgimpl_get_settings().append('disabled')
cfg.val1.val1.pop(0)
assert cfg.val1.val1 == ['yes1']
assert cfg.val1.val2 == ['no1']
def test_callback_master_and_slaves_slave_list():
val1 = StrOption('val1', "", multi=True)
val2 = StrOption('val2', "", multi=True, callback=return_list)
interface1 = OptionDescription('val1', '', [val1, val2])
interface1.impl_set_group_type(groups.master)
maconfig = OptionDescription('rootconfig', '', [interface1])
cfg = Config(maconfig)
cfg.read_write()
#len is equal to 2 for slave and 0 for master
raises(SlaveError, "cfg.val1.val2") raises(SlaveError, "cfg.val1.val2")
cfg.val1.val1 = ['val1', 'val2'] cfg.cfgimpl_get_settings().append('disabled')
assert cfg.val1.val1 == ['val1', 'val2'] raises(ConfigError, "cfg.val1.val1.pop(0)")
assert cfg.val1.val2 == ['val', 'val']
#wrong len
raises(SlaveError, "cfg.val1.val1 = ['val1']")
def test_callback_master_and_slaves_value(): def test_callback_master_and_slaves_value():
@ -687,35 +641,40 @@ def test_callback_master_and_slaves_value():
cfg = Config(maconfig) cfg = Config(maconfig)
cfg.read_write() cfg.read_write()
cfg.val4 == ['val10', 'val11'] cfg.val4 == ['val10', 'val11']
raises(SlaveError, "cfg.val1.val1") assert cfg.val1.val1 == []
raises(SlaveError, "cfg.val1.val2") assert cfg.val1.val2 == []
raises(SlaveError, "cfg.val1.val3") assert cfg.val1.val3 == []
raises(SlaveError, "cfg.val1.val5") assert cfg.val1.val5 == []
raises(SlaveError, "cfg.val1.val6") assert cfg.val1.val6 == []
#raises(SlaveError, "cfg.val1.val1")
#raises(SlaveError, "cfg.val1.val2")
#raises(SlaveError, "cfg.val1.val3")
#raises(SlaveError, "cfg.val1.val5")
#raises(SlaveError, "cfg.val1.val6")
# #
#default calculation has greater length #default calculation has greater length
raises(SlaveError, "cfg.val1.val1 = ['val1']") #raises(SlaveError, "cfg.val1.val1 = ['val1']")
# #
cfg.val1.val1 = ['val1', 'val2'] cfg.val1.val1 = ['val1', 'val2']
assert cfg.val1.val1 == ['val1', 'val2'] assert cfg.val1.val1 == ['val1', 'val2']
assert cfg.val1.val2 == ['val1', 'val2'] assert cfg.val1.val2 == ['val1', 'val2']
assert cfg.val1.val3 == ['yes', 'yes'] assert cfg.val1.val3 == ['yes', 'yes']
assert cfg.val1.val5 == ['val10', 'val11'] raises(SlaveError, "cfg.val1.val5")
assert cfg.val1.val6 == ['val10', 'val11'] raises(SlaveError, "cfg.val1.val6")
# #
cfg.val1.val1.append('val3') cfg.val1.val1.append('val3')
assert cfg.val1.val1 == ['val1', 'val2', 'val3'] assert cfg.val1.val1 == ['val1', 'val2', 'val3']
assert cfg.val1.val2 == ['val1', 'val2', 'val3'] assert cfg.val1.val2 == ['val1', 'val2', 'val3']
assert cfg.val1.val3 == ['yes', 'yes', 'yes'] assert cfg.val1.val3 == ['yes', 'yes', 'yes']
assert cfg.val1.val5 == ['val10', 'val11', None] raises(SlaveError, "cfg.val1.val5")
assert cfg.val1.val6 == ['val10', 'val11', None] raises(SlaveError, "cfg.val1.val6")
# #
cfg.val1.val1.pop(2) cfg.val1.val1.pop(2)
assert cfg.val1.val1 == ['val1', 'val2'] assert cfg.val1.val1 == ['val1', 'val2']
assert cfg.val1.val2 == ['val1', 'val2'] assert cfg.val1.val2 == ['val1', 'val2']
assert cfg.val1.val3 == ['yes', 'yes'] assert cfg.val1.val3 == ['yes', 'yes']
assert cfg.val1.val5 == ['val10', 'val11'] raises(SlaveError, "cfg.val1.val5")
assert cfg.val1.val6 == ['val10', 'val11'] raises(SlaveError, "cfg.val1.val6")
# #
cfg.val1.val2 = ['val2', 'val2'] cfg.val1.val2 = ['val2', 'val2']
cfg.val1.val3 = ['val2', 'val2'] cfg.val1.val3 = ['val2', 'val2']
@ -728,121 +687,16 @@ def test_callback_master_and_slaves_value():
cfg.val1.val1.append('val3') cfg.val1.val1.append('val3')
assert cfg.val1.val2 == ['val2', 'val2', 'val3'] assert cfg.val1.val2 == ['val2', 'val2', 'val3']
assert cfg.val1.val3 == ['val2', 'val2', 'yes'] assert cfg.val1.val3 == ['val2', 'val2', 'yes']
assert cfg.val1.val5 == ['val2', 'val2', None] raises(SlaveError, "cfg.val1.val5")
assert cfg.val1.val6 == ['val2', 'val2', None] raises(SlaveError, "cfg.val1.val6")
cfg.cfgimpl_get_settings().remove('cache') cfg.cfgimpl_get_settings().remove('cache')
cfg.val4 = ['val10', 'val11', 'val12'] cfg.val4 = ['val10', 'val11', 'val12']
#if value is already set, not updated ! #if value is already set, not updated !
cfg.val1.val1.pop(2) cfg.val1.val1.pop(2)
cfg.val1.val1.append('val3') cfg.val1.val1.append('val3')
cfg.val1.val1 = ['val1', 'val2', 'val3'] cfg.val1.val1 = ['val1', 'val2', 'val3']
assert cfg.val1.val5 == ['val2', 'val2', 'val12'] raises(SlaveError, "cfg.val1.val5")
assert cfg.val1.val6 == ['val2', 'val2', 'val12'] raises(SlaveError, "cfg.val1.val6")
def test_callback_master_and_slaves_disabled():
val = BoolOption('val', '', multi=True)
val1 = StrOption('val1', "", multi=True)
val2 = StrOption('val2', "", multi=True, callback=return_value, callback_params={'': ((val, False),)})
interface1 = OptionDescription('val1', '', [val1, val2])
interface1.impl_set_group_type(groups.master)
maconfig = OptionDescription('rootconfig', '', [val, interface1])
cfg = Config(maconfig)
cfg.read_write()
#
assert cfg.val == []
assert cfg.val1.val1 == []
assert cfg.val1.val2 == []
cfg.val1.val1.append('val1')
assert cfg.val == []
assert cfg.val1.val1 == ['val1']
assert cfg.val1.val2 == [None]
#
cfg.val.append(True)
cfg.cfgimpl_get_settings()[cfg.cfgimpl_get_description().val1.val2].append('disabled')
assert cfg.val == [True]
assert cfg.val1.val1 == ['val1']
raises(PropertiesOptionError, 'cfg.val1.val2')
#
cfg.val1.val1.append('val1_1')
assert cfg.val == [True]
assert cfg.val1.val1 == ['val1', 'val1_1']
raises(PropertiesOptionError, 'cfg.val1.val2')
#
cfg.cfgimpl_get_settings()[cfg.cfgimpl_get_description().val1.val2].remove('disabled')
assert cfg.val == [True]
assert cfg.val1.val1 == ['val1', 'val1_1']
raises(ValueError, 'cfg.val1.val2')
#
cfg.val = []
assert cfg.val1.val1 == ['val1', 'val1_1']
assert cfg.val1.val2 == [None, None]
#
cfg.val1.val2 = [None, None]
cfg.val = [True, True]
cfg.cfgimpl_get_settings()[cfg.cfgimpl_get_description().val1.val2].append('disabled')
cfg.val1.val1.pop(1)
assert cfg.val == [True, True]
assert cfg.val1.val1 == ['val1']
raises(PropertiesOptionError, 'cfg.val1.val2')
#
cfg.val1.val1.append('val1_2')
assert cfg.val == [True, True]
assert cfg.val1.val1 == ['val1', 'val1_2']
raises(PropertiesOptionError, 'cfg.val1.val2')
#
cfg.cfgimpl_get_settings()[cfg.cfgimpl_get_description().val1.val2].remove('disabled')
assert cfg.val == [True, True]
assert cfg.val1.val1 == ['val1', 'val1_2']
#[None, None] + pop() + append() => [None, True]
raises(ValueError, 'assert cfg.val1.val2')
def test_callback_master_and_slaves_requires():
val = StrOption('val', '', 'val')
valreq = StrOption('valreq', '', 'val')
val1 = StrOption('val1', "", multi=True)
val2 = StrOption('val2', "", multi=True, callback=return_value, callback_params={'': ((val1, False),)})
val3 = StrOption('val3', "", multi=True, callback=return_value, callback_params={'': ('yes',)})
val4 = StrOption('val4', '', multi=True, default=[])
val5 = StrOption('val5', "", multi=True, callback=return_value, callback_params={'': ((val4, False),)})
val6 = StrOption('val6', "", multi=True, callback=return_value, callback_params={'': ((val, False),)},
requires=({'option': valreq, 'expected': 'val_disabled', 'action': 'disabled'},))
interface1 = OptionDescription('val1', '', [val1, val2, val3, val5, val6])
interface1.impl_set_group_type(groups.master)
maconfig = OptionDescription('rootconfig', '', [val, valreq, interface1, val4])
cfg = Config(maconfig)
cfg.read_write()
assert cfg.val1.val1 == []
assert cfg.val1.val2 == []
assert cfg.val1.val3 == []
assert cfg.val1.val5 == []
assert cfg.val1.val6 == []
#
cfg.val1.val1 = ['val1']
assert cfg.val1.val1 == ['val1']
assert cfg.val1.val2 == ['val1']
assert cfg.val1.val3 == ['yes']
assert cfg.val1.val5 == [None]
assert cfg.val1.val6 == ['val']
cfg.val4 = ['val10']
assert cfg.val1.val5 == ['val10']
#
cfg.valreq = 'val_disabled'
assert cfg.val1.val1 == ['val1']
assert cfg.val1.val2 == ['val1']
assert cfg.val1.val3 == ['yes']
assert cfg.val1.val5 == ['val10']
raises(PropertiesOptionError, 'cfg.val1.val6')
assert cfg.make_dict() == {'val1.val2': ['val1'], 'val1.val3': ['yes'], 'val1.val1': ['val1'], 'val1.val5': ['val10'], 'val': 'val', 'valreq': 'val_disabled', 'val4': ['val10']}
#
cfg.cfgimpl_get_settings()[cfg.cfgimpl_get_description().val].append('disabled')
cfg.cfgimpl_get_settings()[cfg.cfgimpl_get_description().val1.val3].append('disabled')
raises(PropertiesOptionError, 'cfg.val1.val6')
assert cfg.make_dict() == {'val1.val2': ['val1'], 'val1.val1': ['val1'], 'val1.val5': ['val10'], 'val4': ['val10'], 'valreq': 'val_disabled'}
#
cfg.valreq = 'val'
raises(ConfigError, 'cfg.val1.val6')
def test_callback_master(): def test_callback_master():
@ -853,42 +707,6 @@ def test_callback_master():
raises(ValueError, "interface1.impl_set_group_type(groups.master)") raises(ValueError, "interface1.impl_set_group_type(groups.master)")
def test_callback_master_and_other_master_slave():
val1 = StrOption('val1', "", multi=True)
val2 = StrOption('val2', "", multi=True)
val3 = StrOption('val3', "", multi=True)
val4 = StrOption('val4', '', multi=True, default=['val10', 'val11'])
val5 = StrOption('val5', "", multi=True, callback=return_value, callback_params={'': ((val1, False),)})
val6 = StrOption('val6', "", multi=True, callback=return_value, callback_params={'': ((val2, False),)})
interface1 = OptionDescription('val1', '', [val1, val2, val3])
interface1.impl_set_group_type(groups.master)
interface2 = OptionDescription('val4', '', [val4, val5, val6])
interface2.impl_set_group_type(groups.master)
maconfig = OptionDescription('rootconfig', '', [interface1, interface2])
cfg = Config(maconfig)
cfg.read_write()
assert cfg.val4.val4 == ['val10', 'val11']
assert cfg.val4.val5 == [None, None]
assert cfg.val4.val6 == [None, None]
cfg.val1.val1 = ['yes']
assert cfg.val4.val4 == ['val10', 'val11']
assert cfg.val4.val5 == ['yes', None]
assert cfg.val4.val6 == [None, None]
cfg.val1.val2 = ['no']
assert cfg.val4.val4 == ['val10', 'val11']
assert cfg.val4.val5 == ['yes', None]
assert cfg.val4.val6 == ['no', None]
cfg.val1.val1 = ['yes', 'yes', 'yes']
cfg.val1.val2 = ['no', 'no', 'no']
raises(SlaveError, "cfg.val4.val4")
raises(SlaveError, "cfg.val4.val5")
raises(SlaveError, "cfg.val4.val6")
cfg.val4.getattr('val4', validate=False).append('val12')
assert cfg.val4.val4 == ['val10', 'val11', 'val12']
assert cfg.val4.val5 == ['yes', 'yes', 'yes']
assert cfg.val4.val6 == ['no', 'no', 'no']
#FIXME: slave est un symlink #FIXME: slave est un symlink

View file

@ -361,16 +361,16 @@ def test_reset_values_with_master_and_slaves_default():
cfg.ip_admin_eth0.ip_admin_eth0[0] = "192.168.230.146" cfg.ip_admin_eth0.ip_admin_eth0[0] = "192.168.230.146"
cfg.ip_admin_eth0.netmask_admin_eth0[0] = "255.255.255.0" cfg.ip_admin_eth0.netmask_admin_eth0[0] = "255.255.255.0"
assert cfg.getowner(ip_admin_eth0) == owner assert cfg.getowner(ip_admin_eth0) == owner
assert cfg.getowner(netmask_admin_eth0) == owner assert cfg.getowner(netmask_admin_eth0, 0) == owner
del(cfg.ip_admin_eth0.ip_admin_eth0) del(cfg.ip_admin_eth0.ip_admin_eth0)
assert cfg.getowner(ip_admin_eth0) == owners.default assert cfg.getowner(ip_admin_eth0) == owners.default
assert cfg.getowner(netmask_admin_eth0) == owners.default assert cfg.getowner(netmask_admin_eth0, 0) == owners.default
assert cfg.ip_admin_eth0.ip_admin_eth0 == ['192.168.230.145'] assert cfg.ip_admin_eth0.ip_admin_eth0 == ['192.168.230.145']
assert cfg.ip_admin_eth0.netmask_admin_eth0 == [None] assert cfg.ip_admin_eth0.netmask_admin_eth0 == [None]
cfg.ip_admin_eth0.netmask_admin_eth0[0] = "255.255.255.0" cfg.ip_admin_eth0.netmask_admin_eth0[0] = "255.255.255.0"
assert cfg.getowner(ip_admin_eth0) == owners.default assert cfg.getowner(ip_admin_eth0) == owners.default
assert cfg.getowner(netmask_admin_eth0) == owner assert cfg.getowner(netmask_admin_eth0, 0) == owner
del(cfg.ip_admin_eth0.ip_admin_eth0) del(cfg.ip_admin_eth0.ip_admin_eth0)
assert cfg.getowner(ip_admin_eth0) == owners.default assert cfg.getowner(ip_admin_eth0) == owners.default
assert cfg.getowner(netmask_admin_eth0) == owners.default assert cfg.getowner(netmask_admin_eth0) == owners.default

View file

@ -417,10 +417,10 @@ def test_reset_values_with_master_and_slaves_submulti():
cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145") cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145")
cfg.ip_admin_eth0.netmask_admin_eth0[0].append('255.255.255.0') cfg.ip_admin_eth0.netmask_admin_eth0[0].append('255.255.255.0')
assert cfg.getowner(ip_admin_eth0) == owner assert cfg.getowner(ip_admin_eth0) == owner
assert cfg.getowner(netmask_admin_eth0) == owner assert cfg.getowner(netmask_admin_eth0, 0) == owner
del(cfg.ip_admin_eth0.ip_admin_eth0) del(cfg.ip_admin_eth0.ip_admin_eth0)
assert cfg.getowner(ip_admin_eth0) == owners.default assert cfg.getowner(ip_admin_eth0) == owners.default
assert cfg.getowner(netmask_admin_eth0) == owners.default # assert cfg.getowner(netmask_admin_eth0) == owners.default
assert cfg.ip_admin_eth0.ip_admin_eth0 == [] assert cfg.ip_admin_eth0.ip_admin_eth0 == []
assert cfg.ip_admin_eth0.netmask_admin_eth0 == [] assert cfg.ip_admin_eth0.netmask_admin_eth0 == []

View file

@ -18,7 +18,8 @@
# the whole pypy projet is under MIT licence # the whole pypy projet is under MIT licence
# ____________________________________________________________ # ____________________________________________________________
"enables us to carry out a calculation and return an option's value" "enables us to carry out a calculation and return an option's value"
from tiramisu.error import PropertiesOptionError, ConfigError, ContextError from tiramisu.error import PropertiesOptionError, ConfigError, ContextError, \
SlaveError
from tiramisu.i18n import _ from tiramisu.i18n import _
from tiramisu.setting import undefined from tiramisu.setting import undefined
# ____________________________________________________________ # ____________________________________________________________
@ -237,6 +238,9 @@ def carry_out_calculation(option, context, callback, callback_params,
ret = calculate(callback, args, kwargs) ret = calculate(callback, args, kwargs)
if callback_params != {}: if callback_params != {}:
if isinstance(ret, list) and index is not undefined: if isinstance(ret, list) and index is not undefined:
if option.impl_is_master_slaves('slave'):
raise SlaveError(_("callback cannot return a list for a "
"slave option ({0})").format(path))
if len(ret) < index + 1: if len(ret) < index + 1:
ret = None ret = None
else: else:

View file

@ -518,7 +518,7 @@ class _CommonConfig(SubConfig):
"read write is a global config's setting, see `settings.py`" "read write is a global config's setting, see `settings.py`"
self.cfgimpl_get_settings().read_write() self.cfgimpl_get_settings().read_write()
def getowner(self, opt, force_permissive=False): def getowner(self, opt, index=None, force_permissive=False):
"""convenience method to retrieve an option's owner """convenience method to retrieve an option's owner
from the config itself from the config itself
""" """
@ -527,7 +527,7 @@ class _CommonConfig(SubConfig):
not isinstance(opt, DynSymLinkOption): # pragma: optional cover not isinstance(opt, DynSymLinkOption): # pragma: optional cover
raise TypeError(_('opt in getowner must be an option not {0}' raise TypeError(_('opt in getowner must be an option not {0}'
'').format(type(opt))) '').format(type(opt)))
return self.cfgimpl_get_values().getowner(opt, return self.cfgimpl_get_values().getowner(opt, index=index,
force_permissive=force_permissive) force_permissive=force_permissive)
def unwrap_from_path(self, path, force_permissive=False): def unwrap_from_path(self, path, force_permissive=False):
@ -608,12 +608,12 @@ class _CommonConfig(SubConfig):
fake_config = Config(self._impl_descr, persistent=False, fake_config = Config(self._impl_descr, persistent=False,
force_values=get_storages_validation(), force_values=get_storages_validation(),
force_settings=self.cfgimpl_get_settings()) force_settings=self.cfgimpl_get_settings())
fake_config.cfgimpl_get_values()._p_._values = self.cfgimpl_get_values()._p_.get_modified_values() fake_config.cfgimpl_get_values()._p_._values = self.cfgimpl_get_values()._p_._values
return fake_config return fake_config
def duplicate(self): def duplicate(self):
config = Config(self._impl_descr) config = Config(self._impl_descr)
config.cfgimpl_get_values()._p_._values = self.cfgimpl_get_values()._p_.get_modified_values() config.cfgimpl_get_values()._p_._values = self.cfgimpl_get_values()._p_._values
config.cfgimpl_get_settings()._p_._properties = self.cfgimpl_get_settings()._p_.get_modified_properties() config.cfgimpl_get_settings()._p_._properties = self.cfgimpl_get_settings()._p_.get_modified_properties()
config.cfgimpl_get_settings()._p_._permissives = self.cfgimpl_get_settings()._p_.get_modified_permissives() config.cfgimpl_get_settings()._p_._permissives = self.cfgimpl_get_settings()._p_.get_modified_permissives()
return config return config

View file

@ -98,7 +98,8 @@ 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=undefined): 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:
@ -108,7 +109,7 @@ class Base(StorageBase):
calc_properties = frozenset() calc_properties = frozenset()
requires = undefined requires = undefined
if not multi and default_multi is not None: # pragma: optional cover if not multi and default_multi is not None: # pragma: optional cover
raise ValueError(_("a default_multi is set whereas multi is False" raise ValueError(_("default_multi is set whereas multi is False"
" in option: {0}").format(name)) " in option: {0}").format(name))
if multi is True: if multi is True:
_multi = 0 _multi = 0
@ -133,7 +134,8 @@ class Base(StorageBase):
'requirement {0}'.format( 'requirement {0}'.format(
list(set_forbidden_properties))) list(set_forbidden_properties)))
StorageBase.__init__(self, name, _multi, warnings_only, doc, extra, StorageBase.__init__(self, name, _multi, warnings_only, doc, extra,
calc_properties, requires, properties, allow_empty_list) calc_properties, requires, properties,
allow_empty_list)
if multi is not False and default is None: if multi is not False and default is None:
default = [] default = []
self.impl_validate(default) self.impl_validate(default)

View file

@ -48,6 +48,10 @@ class MasterSlaves(object):
if child.impl_getname() == name: if child.impl_getname() == name:
self.master = child self.master = child
else: else:
if child.impl_getdefault() != []:
raise ValueError(_("not allowed default value for option {0} "
"in group {1}").format(child.impl_getname(),
name))
slaves.append(child) slaves.append(child)
if self.master is None: # pragma: optional cover if self.master is None: # pragma: optional cover
raise ValueError(_('master group with wrong' raise ValueError(_('master group with wrong'
@ -107,7 +111,7 @@ class MasterSlaves(object):
def pop(self, opt, values, index): def pop(self, opt, values, index):
for slave in self.getslaves(opt): for slave in self.getslaves(opt):
if not values.is_default_owner(slave, validate_properties=False, if not values.is_default_owner(slave, validate_properties=False,
validate_meta=False): validate_meta=False, index=index):
values._get_cached_item(slave, validate=False, values._get_cached_item(slave, validate=False,
validate_properties=False validate_properties=False
).pop(index, force=True) ).pop(index, force=True)
@ -139,17 +143,19 @@ class MasterSlaves(object):
for slave in self.getslaves(opt): for slave in self.getslaves(opt):
try: try:
slave_path = slave.impl_getpath(values._getcontext()) slave_path = slave.impl_getpath(values._getcontext())
if c_slave_path == slave_path: slavelen = values._p_.get_max_length(slave_path)
slave_value = c_slave_value #if c_slave_path == slave_path:
else: # slave_value = c_slave_value
slave_value = values._get_validated_value(slave, #else:
slave_path, # slave_value = values._get_validated_value(slave,
False, # slave_path,
False, # False,
None, False, # False,
None, # None, False,
self_properties=self_properties) # None,
slavelen = len(slave_value) # self_properties=self_properties,
# masterlen=masterlen)
#slavelen = len(slave_value)
self.validate_slave_length(masterlen, slavelen, slave.impl_getname(), opt) self.validate_slave_length(masterlen, slavelen, slave.impl_getname(), opt)
except ConfigError: # pragma: optional cover except ConfigError: # pragma: optional cover
pass pass
@ -186,31 +192,36 @@ class MasterSlaves(object):
undefined, force_permissive, undefined, force_permissive,
master=master) master=master)
master_is_meta = values._is_meta(opt, masterp) master_is_meta = values._is_meta(opt, masterp)
value = values._get_validated_value(opt, path, validate, #value = values._get_validated_value(opt, path, validate,
force_permissive, # force_permissive,
force_properties, # force_properties,
validate_properties, # validate_properties,
None, # not undefined # None, # not undefined
with_meta=master_is_meta, # with_meta=master_is_meta,
self_properties=self_properties) # self_properties=self_properties)
#if slave, had values until master's one #if slave, had values until master's one
path = opt.impl_getpath(context) #path = opt.impl_getpath(context)
valuelen = len(value) #valuelen = len(value)
if validate: #if validate:
self.validate_slave_length(masterlen, valuelen, # self.validate_slave_length(masterlen, valuelen,
opt.impl_getname(), opt) # opt.impl_getname(), opt)
if valuelen < masterlen: #if valuelen < masterlen:
for num in range(0, masterlen - valuelen):
index = valuelen + num #FIXME voir si pas de plus grande valeur !
value.append(values._get_validated_value(opt, path, True, value = values._get_multi(opt, path)
False, None, for index in range(0, masterlen):
validate_properties=False, #index = valuelen + num
value.append(values._get_validated_value(opt, path, validate,
force_permissive, force_properties,
validate_properties,
with_meta=master_is_meta, with_meta=master_is_meta,
index=index, index=index,
self_properties=self_properties), self_properties=self_properties,
masterlen=masterlen),
setitem=False, setitem=False,
force=True, force=True,
validate=validate) validate=validate)
#FIXME hu?
if validate_properties: if validate_properties:
context.cfgimpl_get_settings().validate_properties(opt, False, context.cfgimpl_get_settings().validate_properties(opt, False,
False, False,
@ -228,14 +239,17 @@ class MasterSlaves(object):
base_path = '.'.join(path.split('.')[:-1]) + '.' base_path = '.'.join(path.split('.')[:-1]) + '.'
for slave in self.getslaves(opt): for slave in self.getslaves(opt):
slave_path = base_path + slave.impl_getname() slave_path = base_path + slave.impl_getname()
slave_value = values._get_validated_value(slave, slavelen = values._p_.get_max_length(slave_path)
slave_path,
False,
False,
None, False,
None) # not undefined
slavelen = len(slave_value)
self.validate_slave_length(masterlen, slavelen, slave.impl_getname(), opt) self.validate_slave_length(masterlen, slavelen, slave.impl_getname(), opt)
#slave_value = values._get_validated_value(slave,
# slave_path,
# False,
# False,
# None, False,
# None,
# masterlen=masterlen) # not undefined
#slavelen = len(slave_value)
#self.validate_slave_length(masterlen, slavelen, slave.impl_getname(), opt)
else: else:
self.validate_slave_length(self.get_length(values, opt, self.validate_slave_length(self.get_length(values, opt,
slave_path=path), len(value), slave_path=path), len(value),

View file

@ -433,7 +433,8 @@ class Settings(object):
value=None, force_permissive=False, value=None, force_permissive=False,
force_properties=None, force_properties=None,
setting_properties=undefined, setting_properties=undefined,
self_properties=undefined): self_properties=undefined,
index=None):
""" """
validation upon the properties related to `opt_or_descr` validation upon the properties related to `opt_or_descr`
@ -480,7 +481,7 @@ 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, value, index=index):
properties.remove('mandatory') properties.remove('mandatory')
elif opt_or_descr.impl_is_multi() and \ elif opt_or_descr.impl_is_multi() and \
not is_write and 'empty' in forced_properties and \ not is_write and 'empty' in forced_properties and \

View file

@ -47,7 +47,7 @@ class StorageBase(object):
'_master_slaves', '_master_slaves',
'_choice_values', '_choice_values',
'_choice_values_params', '_choice_values_params',
#autre #other
'_state_master_slaves', '_state_master_slaves',
'_state_callback', '_state_callback',
'_state_callback_params', '_state_callback_params',

View file

@ -15,8 +15,8 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # along with this program. If not, see <http://www.gnu.org/licenses/>.
# ____________________________________________________________ # ____________________________________________________________
from copy import copy
from ..util import Cache from ..util import Cache
from tiramisu.setting import undefined
class Values(Cache): class Values(Cache):
@ -25,52 +25,167 @@ class Values(Cache):
def __init__(self, storage): def __init__(self, storage):
"""init plugin means create values storage """init plugin means create values storage
""" """
self._values = {} self._values = (tuple(), tuple(), tuple(), tuple())
self._informations = {} self._informations = {}
# should init cache too # should init cache too
super(Values, self).__init__(storage) super(Values, self).__init__(storage)
# value # value
def setvalue(self, path, value, owner): def setvalue(self, path, value, owner, index):
"""set value for a path """set value for a path
a specified value must be associated to an owner a specified value must be associated to an owner
""" """
self._values[path] = (owner, value) values = []
vidx = None
def getvalue(self, path): def _setvalue_info(nb, idx, value, vidx):
lst = list(self._values[nb])
if idx is None:
if index is None or nb == 0:
lst.append(value)
else:
lst.append([value])
else:
if index is None or nb == 0:
lst[idx] = value
else:
if nb == 1:
try:
vidx = lst[idx].index(index)
except ValueError:
vidx = None
if vidx is None:
lst[idx].append(value)
elif nb != 1:
lst[idx][vidx] = value
values.append(tuple(lst))
return vidx
try:
idx = self._values[0].index(path)
except ValueError:
idx = None
vidx = _setvalue_info(0, idx, path, vidx)
vidx = _setvalue_info(1, idx, index, vidx)
vidx = _setvalue_info(2, idx, value, vidx)
_setvalue_info(3, idx, owner, vidx)
self._values = tuple(values)
def getvalue(self, path, index=None):
"""get value for a path """get value for a path
return: only value, not the owner return: only value, not the owner
""" """
return self._values[path][1] return self._getvalue(path, 2, index)
def hasvalue(self, path): def hasvalue(self, path, index=None):
"""if path has a value """if path has a value
return: boolean return: boolean
""" """
return path in self._values return path in self._values[0]
def resetvalue(self, path): def resetvalue(self, path):
"""remove value means delete value in storage """remove value means delete value in storage
""" """
del(self._values[path]) def _resetvalue(nb):
lst = list(self._values[nb])
lst.pop(idx)
values.append(tuple(lst))
values = []
idx = self._values[0].index(path)
_resetvalue(0)
_resetvalue(1)
_resetvalue(2)
_resetvalue(3)
self._values = tuple(values)
def get_modified_values(self): def get_modified_values(self):
"""return all values in a dictionary """return all values in a dictionary
example: {'path1': (owner, 'value1'), 'path2': (owner, 'value2')} example: {'path1': (owner, 'value1'), 'path2': (owner, 'value2')}
""" """
return copy(self._values) values = {}
for idx, path in enumerate(self._values[0]):
values[path] = (self._values[3][idx], self._values[2][idx])
return values
# owner # owner
def setowner(self, path, owner): def setowner(self, path, owner, index=None):
"""change owner for a path """change owner for a path
""" """
self._values[path] = (owner, self._values[path][1]) idx = self._values[0].index(path)
if isinstance(self._values[3][idx], list):
if index is None:
raise ValueError('list but no index')
owner = list(self._values[3][idx])[index] = owner
elif index is not None:
raise ValueError('index set but not a list')
lst = list(self._values[3])
lst[idx] = owner
values = list(self._values)
values[3] = tuple(lst)
self._values = tuple(values)
def getowner(self, path, default): def get_max_length(self, path):
try:
idx = self._values[0].index(path)
except ValueError:
return 0
return max(self._values[1][idx]) + 1
def getowner(self, path, default, index=None, only_default=False):
"""get owner for a path """get owner for a path
return: owner object return: owner object
""" """
return self._values.get(path, (default, None))[0] if index is None:
if only_default:
if path in self._values[0]:
return None
else:
return default
val = self._getvalue(path, 3, index)
if val is None:
return default
return val
else:
value = self._getvalue(path, 3, index)
if value is None:
return default
else:
return value
def _getvalue(self, path, nb, index):
"""
_values == ((path1, path2), ((value1_1, value1_2), value2), ((owner1_1, owner1_2), owner2), ((idx1_1, idx1_2), None))
"""
try:
idx = self._values[0].index(path)
except ValueError:
value = None
else:
if isinstance(self._values[1][idx], list):
if index is None:
raise ValueError('list but no index')
elif index is not None:
raise ValueError('index set but not a list')
if self._values[1][idx] is None:
if index is None:
value = self._values[nb][idx]
else:
value = self._values[nb][idx][index]
else:
if index is not None:
try:
subidx = self._values[1][idx].index(index)
value = self._values[nb][idx][subidx]
except ValueError:
value = None
else:
value = []
for i in xrange(0, max(self._values[1][idx])):
if i in self._values[1][idx]:
value.append(self._values[nb][idx][self._values[1][idx].index(i)])
else:
value.append(undefined)
return value
def set_information(self, key, value): def set_information(self, key, value):
"""updates the information's attribute """updates the information's attribute

View file

@ -47,11 +47,20 @@ class Cache(object):
value = getattr(self, slot) value = getattr(self, slot)
#value has owners object, need 'str()' it #value has owners object, need 'str()' it
if slot == '_values': if slot == '_values':
_value = {} _value = []
for key, values in value.items(): _value.append(value[0])
vals = list(values) _value.append(value[1])
vals[0] = str(vals[0]) str_owner = []
_value[key] = tuple(vals) _value.append(value[2])
for owner in value[3]:
if isinstance(owner, list):
str_owners = []
for subowner in owner:
str_owners.append(str(subowner))
str_owner.append(str_owners)
else:
str_owner.append(str(owner))
_value.append(str_owner)
states[slot] = _value states[slot] = _value
else: else:
states[slot] = value states[slot] = value
@ -60,19 +69,32 @@ class Cache(object):
return states return states
def __setstate__(self, states): def __setstate__(self, states):
def convert_owner(owner):
try:
owner = getattr(owners, owner)
except AttributeError:
owners.addowner(owner)
owner = getattr(owners, owner)
return owner
for key, value in states.items(): for key, value in states.items():
#value has owners object, need to reconstruct it #value has owners object, need to reconstruct it
if key == '_values': if key == '_values':
_value = {} _value = []
for key_, values_ in value.items(): _value.append(value[0])
vals = list(values_) _value.append(value[1])
try: _value.append(value[2])
vals[0] = getattr(owners, vals[0]) obj_owner = []
except AttributeError: for owner in value[3]:
owners.addowner(vals[0]) if isinstance(owner, list):
vals[0] = getattr(owners, vals[0]) obj_owners = []
_value[key_] = tuple(vals) for subowner in owner:
value = _value obj_owners.append(convert_owner(subowner))
obj_owner.append(tuple(obj_owners))
else:
obj_owner.append(convert_owner(owner))
_value.append(tuple(obj_owner))
value = tuple(_value)
setattr(self, key, value) setattr(self, key, value)
def setcache(self, path, val, time): def setcache(self, path, val, time):

View file

@ -54,33 +54,10 @@ class Values(object):
raise ConfigError(_('the context does not exist anymore')) raise ConfigError(_('the context does not exist anymore'))
return context return context
def _getvalue(self, opt, path, is_default, index=undefined, def _get_multi(self, opt, path):
with_meta=True, self_properties=undefined): return Multi([], self.context, opt, path)
"""actually retrieves the value
:param opt: the `option.Option()` object def _getdefaultvalue(self, opt, path, with_meta, index):
:returns: the option's value (or the default value if not set)
"""
if opt.impl_is_optiondescription(): # pragma: optional cover
raise ValueError(_('optiondescription has no value'))
if self_properties is undefined:
self_properties = self._getcontext().cfgimpl_get_settings()._getproperties(
opt, path, read_write=False)
force_default = 'frozen' in self_properties and \
'force_default_on_freeze' in self_properties
if not is_default and not force_default:
value = self._p_.getvalue(path)
if index is not undefined:
try:
return value[index]
except IndexError:
#value is smaller than expected
#so return default value
pass
else:
return value
#so default value
# if value has callback and is not set # if value has callback and is not set
if opt.impl_has_callback(): if opt.impl_has_callback():
callback, callback_params = opt.impl_get_callback() callback, callback_params = opt.impl_get_callback()
@ -126,6 +103,56 @@ class Values(object):
value = opt.impl_getdefault_multi() value = opt.impl_getdefault_multi()
return value return value
def _getvalue(self, opt, path, is_default, index=undefined,
with_meta=True, self_properties=undefined,
masterlen=undefined):
"""actually retrieves the value
:param opt: the `option.Option()` object
:returns: the option's value (or the default value if not set)
"""
if opt.impl_is_optiondescription(): # pragma: optional cover
raise ValueError(_('optiondescription has no value'))
if self_properties is undefined:
self_properties = self._getcontext().cfgimpl_get_settings()._getproperties(
opt, path, read_write=False)
force_default = 'frozen' in self_properties and \
'force_default_on_freeze' in self_properties
if not is_default and not force_default:
if opt.impl_is_master_slaves('slave'):
#if masterlen is not undefined:
if index is undefined:
value = []
vals = self._p_.getvalue(path)
length = max(masterlen, len(vals))
for idx in xrange(0, length):
try:
if vals[idx] is undefined:
value.append(self._getdefaultvalue(opt, path, with_meta, idx))
else:
value.append(vals[idx])
except IndexError:
try:
value.append(self._getdefaultvalue(opt, path, with_meta, idx))
except IndexError:
value.append(None)
else:
value = self._p_.getvalue(path, index)
return value
else:
value = self._p_.getvalue(path)
if index is not undefined:
try:
return value[index]
except IndexError:
#value is smaller than expected
#so return default value
pass
else:
return value
return self._getdefaultvalue(opt, path, with_meta, index)
def get_modified_values(self): def get_modified_values(self):
context = self._getcontext() context = self._getcontext()
if context._impl_descr is not None: if context._impl_descr is not None:
@ -175,13 +202,13 @@ class Values(object):
if hasvalue: if hasvalue:
self._p_.resetvalue(path) self._p_.resetvalue(path)
def _isempty(self, opt, value, force_allow_empty_list=False): def _isempty(self, opt, value, force_allow_empty_list=False, index=None):
"convenience method to know if an option is empty" "convenience method to know if an option is empty"
if value is undefined: if value is undefined:
return False return False
else: else:
empty = opt._empty empty = opt._empty
if opt.impl_is_multi(): if index in [None, undefined] and opt.impl_is_multi():
if force_allow_empty_list: if force_allow_empty_list:
allow_empty_list = True allow_empty_list = True
else: else:
@ -273,7 +300,7 @@ class Values(object):
force_properties, validate_properties, force_properties, validate_properties,
index=undefined, submulti_index=undefined, index=undefined, submulti_index=undefined,
with_meta=True, setting_properties=undefined, with_meta=True, setting_properties=undefined,
self_properties=undefined): self_properties=undefined, masterlen=undefined):
"""same has getitem but don't touch the cache """same has getitem but don't touch the cache
index is None for slave value, if value returned is not a list, just return [] index is None for slave value, if value returned is not a list, just return []
""" """
@ -286,7 +313,8 @@ class Values(object):
is_default = self._is_default_owner(opt, path, is_default = self._is_default_owner(opt, path,
validate_properties=False, validate_properties=False,
validate_meta=False, validate_meta=False,
self_properties=self_properties) self_properties=self_properties,
index=index)
try: try:
if index is None: if index is None:
gv_index = undefined gv_index = undefined
@ -294,7 +322,8 @@ class Values(object):
gv_index = index gv_index = index
value = self._getvalue(opt, path, is_default, index=gv_index, value = self._getvalue(opt, path, is_default, index=gv_index,
with_meta=with_meta, with_meta=with_meta,
self_properties=self_properties) self_properties=self_properties,
masterlen=masterlen)
config_error = None config_error = None
except ConfigError as err: except ConfigError as err:
# For calculating properties, we need value (ie for mandatory # For calculating properties, we need value (ie for mandatory
@ -309,8 +338,7 @@ class Values(object):
# value is not set, for 'undefined' (cannot set None because of # value is not set, for 'undefined' (cannot set None because of
# mandatory property) # mandatory property)
value = undefined value = undefined
else:
if config_error is None:
if index is undefined: if index is undefined:
force_index = None force_index = None
else: else:
@ -358,7 +386,8 @@ class Values(object):
force_permissive=force_permissive, force_permissive=force_permissive,
force_properties=force_properties, force_properties=force_properties,
setting_properties=setting_properties, setting_properties=setting_properties,
self_properties=self_properties) self_properties=self_properties,
index=index)
if config_error is not None: if config_error is not None:
raise config_error raise config_error
return value return value
@ -394,7 +423,7 @@ class Values(object):
def _setvalue(self, opt, path, value, force_permissive=False, def _setvalue(self, opt, path, value, force_permissive=False,
is_write=True, validate_properties=True, is_write=True, validate_properties=True,
setting_properties=undefined): setting_properties=undefined, index=None):
context = self._getcontext() context = self._getcontext()
context.cfgimpl_reset_cache() context.cfgimpl_reset_cache()
if validate_properties: if validate_properties:
@ -410,7 +439,15 @@ class Values(object):
if isinstance(val, SubMulti): if isinstance(val, SubMulti):
value[idx] = list(val) value[idx] = list(val)
owner = context.cfgimpl_get_settings().getowner() owner = context.cfgimpl_get_settings().getowner()
self._p_.setvalue(path, value, owner) if opt.impl_is_master_slaves('slave') and index is None:
try:
self._p_.resetvalue(path)
except ValueError:
pass
for idx, val in enumerate(value):
self._p_.setvalue(path, val, owner, idx)
else:
self._p_.setvalue(path, value, owner, index)
def _is_meta(self, opt, path): def _is_meta(self, opt, path):
context = self._getcontext() context = self._getcontext()
@ -418,13 +455,13 @@ class Values(object):
self_properties = setting._getproperties(opt, path, read_write=False) self_properties = setting._getproperties(opt, path, read_write=False)
if 'frozen' in self_properties and 'force_default_on_freeze' in self_properties: if 'frozen' in self_properties and 'force_default_on_freeze' in self_properties:
return False return False
if self._p_.getowner(path, owners.default) is not owners.default: if self._p_.getowner(path, owners.default, only_default=True) is not owners.default:
return False return False
if context.cfgimpl_get_meta() is not None: if context.cfgimpl_get_meta() is not None:
return True return True
return False return False
def getowner(self, opt, force_permissive=False): def getowner(self, opt, index=None, force_permissive=False):
""" """
retrieves the option's owner retrieves the option's owner
@ -437,11 +474,12 @@ class Values(object):
not isinstance(opt, DynSymLinkOption): not isinstance(opt, DynSymLinkOption):
opt = opt._impl_getopt() opt = opt._impl_getopt()
path = opt.impl_getpath(self._getcontext()) path = opt.impl_getpath(self._getcontext())
return self._getowner(opt, path, force_permissive=force_permissive) return self._getowner(opt, path, index=index, force_permissive=force_permissive)
def _getowner(self, opt, path, validate_properties=True, def _getowner(self, opt, path, validate_properties=True,
force_permissive=False, validate_meta=undefined, force_permissive=False, validate_meta=undefined,
self_properties=undefined): self_properties=undefined, only_default=False,
index=None):
"""get owner of an option """get owner of an option
""" """
if not isinstance(opt, Option) and not isinstance(opt, if not isinstance(opt, Option) and not isinstance(opt,
@ -456,7 +494,7 @@ class Values(object):
if validate_properties: if validate_properties:
self._getitem(opt, path, True, force_permissive, None, True, self._getitem(opt, path, True, force_permissive, None, True,
self_properties=self_properties) self_properties=self_properties)
owner = self._p_.getowner(path, owners.default) owner = self._p_.getowner(path, owners.default, only_default=only_default, index=index)
if validate_meta is undefined: if validate_meta is undefined:
if opt.impl_is_master_slaves('slave'): if opt.impl_is_master_slaves('slave'):
master = opt.impl_get_master_slaves().getmaster(opt) master = opt.impl_get_master_slaves().getmaster(opt)
@ -467,7 +505,11 @@ class Values(object):
if validate_meta: if validate_meta:
meta = context.cfgimpl_get_meta() meta = context.cfgimpl_get_meta()
if owner is owners.default and meta is not None: if owner is owners.default and meta is not None:
owner = meta.cfgimpl_get_values()._getowner(opt, path) owner = meta.cfgimpl_get_values()._getowner(opt, path,
validate_properties=validate_properties,
force_permissive=force_permissive,
self_properties=self_properties,
only_default=only_default, index=index)
return owner return owner
def setowner(self, opt, owner): def setowner(self, opt, owner):
@ -481,9 +523,6 @@ class Values(object):
raise TypeError(_("invalid generic owner {0}").format(str(owner))) raise TypeError(_("invalid generic owner {0}").format(str(owner)))
path = opt.impl_getpath(self._getcontext()) path = opt.impl_getpath(self._getcontext())
self._setowner(opt, path, owner)
def _setowner(self, opt, path, owner):
if not self._p_.hasvalue(path): # pragma: optional cover if not self._p_.hasvalue(path): # pragma: optional cover
raise ConfigError(_('no value for {0} cannot change owner to {1}' raise ConfigError(_('no value for {0} cannot change owner to {1}'
'').format(path, owner)) '').format(path, owner))
@ -495,7 +534,7 @@ class Values(object):
self._p_.setowner(path, owner) self._p_.setowner(path, owner)
def is_default_owner(self, opt, validate_properties=True, def is_default_owner(self, opt, validate_properties=True,
validate_meta=True): validate_meta=True, index=None):
""" """
:param config: *must* be only the **parent** config :param config: *must* be only the **parent** config
(not the toplevel config) (not the toplevel config)
@ -504,14 +543,18 @@ class Values(object):
path = opt.impl_getpath(self._getcontext()) path = opt.impl_getpath(self._getcontext())
return self._is_default_owner(opt, path, return self._is_default_owner(opt, path,
validate_properties=validate_properties, validate_properties=validate_properties,
validate_meta=validate_meta) validate_meta=validate_meta, index=index)
def _is_default_owner(self, opt, path, validate_properties=True, def _is_default_owner(self, opt, path, validate_properties=True,
validate_meta=True, self_properties=undefined): validate_meta=True, self_properties=undefined,
return self._getowner(opt, path, validate_properties, index=None):
if not opt.impl_is_master_slaves('slave'):
index = None
d = self._getowner(opt, path, validate_properties,
validate_meta=validate_meta, validate_meta=validate_meta,
self_properties=self_properties) == \ self_properties=self_properties, only_default=True,
owners.default index=index)
return d == owners.default
def reset_cache(self, only_expired): def reset_cache(self, only_expired):
""" """
@ -640,7 +683,6 @@ class Values(object):
# ____________________________________________________________ # ____________________________________________________________
# multi types # multi types
class Multi(list): class Multi(list):
"""multi options values container """multi options values container
that support item notation for the values of multi options""" that support item notation for the values of multi options"""
@ -708,7 +750,7 @@ class Multi(list):
self._validate(value, fake_context, index, True) self._validate(value, fake_context, index, True)
#assume not checking mandatory property #assume not checking mandatory property
super(Multi, self).__setitem__(index, value) super(Multi, self).__setitem__(index, value)
context.cfgimpl_get_values()._setvalue(self.opt, self.path, self, setting_properties=setting_properties) self._store()
#def __repr__(self, *args, **kwargs): #def __repr__(self, *args, **kwargs):
# return super(Multi, self).__repr__(*args, **kwargs) # return super(Multi, self).__repr__(*args, **kwargs)
@ -750,7 +792,7 @@ class Multi(list):
value.submulti = weakref.ref(self) value.submulti = weakref.ref(self)
super(Multi, self).append(value) super(Multi, self).append(value)
if setitem: if setitem:
self._store(force) self._store(force=force)
def sort(self, cmp=None, key=None, reverse=False): def sort(self, cmp=None, key=None, reverse=False):
if self.opt.impl_is_master_slaves(): if self.opt.impl_is_master_slaves():
@ -773,7 +815,6 @@ class Multi(list):
self._store() self._store()
def insert(self, index, value, validate=True): def insert(self, index, value, validate=True):
#FIXME value should be undefined
if self.opt.impl_is_master_slaves(): if self.opt.impl_is_master_slaves():
raise SlaveError(_("cannot insert multi option {0} if master or " raise SlaveError(_("cannot insert multi option {0} if master or "
"slave").format(self.opt.impl_getname())) "slave").format(self.opt.impl_getname()))
@ -833,7 +874,7 @@ class Multi(list):
context.cfgimpl_get_values(), index) context.cfgimpl_get_values(), index)
#set value without valid properties #set value without valid properties
ret = super(Multi, self).pop(index) ret = super(Multi, self).pop(index)
self._store(force) self._store(force=force)
return ret return ret
def _store(self, force=False): def _store(self, force=False):