add DynOptionDescription

This commit is contained in:
Emmanuel Garette 2014-06-19 23:22:39 +02:00
parent 888446e4c5
commit b64189f763
21 changed files with 2382 additions and 543 deletions

View File

@ -1,3 +1,9 @@
Thu Jun 19 23:20:29 2014 +0200 Emmanuel Garette <egarette@cadoles.com>
* add DynOptionDescription:
DynOptionDescription are OptionDescription that generate auto
OptionDescription with a callback function
Sun Apr 27 10:32:40 2014 +0200 Emmanuel Garette <egarette@cadoles.com>
* behavior change in ChoiceOption:

View File

@ -0,0 +1,87 @@
# coding: utf-8
import autopath
from tiramisu.setting import owners
from tiramisu.option import ChoiceOption, StrOption, OptionDescription
from tiramisu.config import Config
from py.test import raises
def return_val(val):
return val
def return_list():
return ['val1', 'val2']
def return_calc_list(val):
return [val]
def test_choiceoption_function():
ch = ChoiceOption('ch', '', values=return_list)
od = OptionDescription('od', '', [ch])
cfg = Config(od)
cfg.read_write()
owner = cfg.cfgimpl_get_settings().getowner()
assert cfg.getowner(ch) == owners.default
cfg.ch = 'val1'
assert cfg.getowner(ch) == owner
del(cfg.ch)
assert cfg.getowner(ch) == owners.default
raises(ValueError, "cfg.ch='no'")
assert cfg.getowner(ch) == owners.default
def test_choiceoption_calc_function():
ch = ChoiceOption('ch', "", values=return_calc_list, values_params={'': ('val1',)})
od = OptionDescription('od', '', [ch])
cfg = Config(od)
cfg.read_write()
owner = cfg.cfgimpl_get_settings().getowner()
assert cfg.getowner(ch) == owners.default
cfg.ch = 'val1'
assert cfg.getowner(ch) == owner
del(cfg.ch)
assert cfg.getowner(ch) == owners.default
raises(ValueError, "cfg.ch='no'")
assert cfg.getowner(ch) == owners.default
def test_choiceoption_calc_opt_function():
st = StrOption('st', '', 'val1')
ch = ChoiceOption('ch', "", values=return_calc_list, values_params={'': ((st, False),)})
od = OptionDescription('od', '', [st, ch])
cfg = Config(od)
cfg.read_write()
owner = cfg.cfgimpl_get_settings().getowner()
assert cfg.getowner(ch) == owners.default
cfg.ch = 'val1'
assert cfg.getowner(ch) == owner
del(cfg.ch)
assert cfg.getowner(ch) == owners.default
raises(ValueError, "cfg.ch='no'")
assert cfg.getowner(ch) == owners.default
def test_choiceoption_calc_opt_multi_function():
st = StrOption('st', '', ['val1'], multi=True)
ch = ChoiceOption('ch', "", default_multi='val2', values=return_val, values_params={'': ((st, False),)}, multi=True)
ch2 = ChoiceOption('ch2', "", default=['val2'], values=return_val, values_params={'': ((st, False),)}, multi=True)
od = OptionDescription('od', '', [st, ch, ch2])
cfg = Config(od)
cfg.read_write()
assert cfg.ch == []
owner = cfg.cfgimpl_get_settings().getowner()
assert cfg.getowner(ch) == owners.default
raises(ValueError, "cfg.ch.append()")
cfg.ch = ['val1']
assert cfg.getowner(ch) == owner
del(cfg.ch)
assert cfg.getowner(ch) == owners.default
raises(ValueError, "cfg.ch='no'")
assert cfg.getowner(ch) == owners.default
#
raises(ValueError, "cfg.ch2")

View File

@ -0,0 +1,1317 @@
# coding: utf-8
import autopath
from tiramisu.setting import groups, owners
from tiramisu.option import BoolOption, StrOption, ChoiceOption, IPOption, \
NetworkOption, NetmaskOption, IntOption, FloatOption, \
UnicodeOption, PortOption, BroadcastOption, DomainnameOption, \
EmailOption, URLOption, UsernameOption, FilenameOption, SymLinkOption, \
OptionDescription, DynOptionDescription, DynSymLinkOption, submulti
from tiramisu.config import Config
from tiramisu.error import PropertiesOptionError, ConfigError, ConflictError
from tiramisu.storage import delete_session
from test.test_state import _diff_opts, _diff_conf
from py.test import raises
from pickle import dumps, loads
def return_true(value, param=None):
if value == 'val' and param in [None, 'yes']:
return
raise ValueError('no value')
def return_dynval(suffix, value='val'):
return value
def return_list2(suffix):
return [suffix, 'val2']
def return_list(val=None):
if val:
return val
else:
return ['val1', 'val2']
def test_build_dyndescription():
st = StrOption('st', '')
dod = DynOptionDescription('dod', '', [st], callback=return_list)
od = OptionDescription('od', '', [dod])
cfg = Config(od)
assert str(cfg) == """[dodval1]
[dodval2]"""
assert str(cfg.dodval1) == "stval1 = None"
assert str(cfg.dodval2) == "stval2 = None"
def test_subpath_dyndescription():
st = StrOption('st', '')
dod = DynOptionDescription('dod', '', [st], callback=return_list)
od = OptionDescription('od', '', [dod])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
assert str(cfg) == "[od]"
assert str(cfg.od) == """[dodval1]
[dodval2]"""
assert str(cfg.od.dodval1) == "stval1 = None"
assert str(cfg.od.dodval2) == "stval2 = None"
def test_list_dyndescription():
st = StrOption('st', '')
dod = DynOptionDescription('dod', '', [st], callback=return_list)
od = OptionDescription('od', '', [dod])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
assert cfg.od.dodval1.stval1 is None
assert cfg.od.dodval2.stval2 is None
def test_unknown_dyndescription():
st = StrOption('st', '')
dod = DynOptionDescription('dod', '', [st], callback=return_list)
od = OptionDescription('od', '', [dod])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
raises(AttributeError, "cfg.od.dodval3")
raises(AttributeError, "cfg.od.dodval1.novalue")
def test_getdoc_dyndescription():
st = StrOption('st', 'doc1')
dod = DynOptionDescription('dod', 'doc2', [st], callback=return_list)
od = OptionDescription('od', '', [dod])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
dodval1 = cfg.unwrap_from_path('od.dodval1')
dodval2 = cfg.unwrap_from_path('od.dodval2')
assert stval1.impl_getname() == 'stval1'
assert stval2.impl_getname() == 'stval2'
assert dodval1.impl_getname() == 'dodval1'
assert dodval2.impl_getname() == 'dodval2'
assert stval1.impl_getdoc() == 'doc1'
assert stval2.impl_getdoc() == 'doc1'
assert dodval1.impl_getdoc() == 'doc2'
assert dodval2.impl_getdoc() == 'doc2'
def test_getpaths_dyndescription():
st = StrOption('st', '')
dod = DynOptionDescription('dod', '', [st], callback=return_list)
od = OptionDescription('od', '', [dod])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
assert cfg.cfgimpl_get_description().impl_getpaths() == ['od.dodval1.stval1', 'od.dodval2.stval2']
assert cfg.cfgimpl_get_description().impl_getpaths(include_groups=True) == ['od', 'od.dodval1', 'od.dodval1.stval1', 'od.dodval2', 'od.dodval2.stval2']
def test_mod_dyndescription():
st = StrOption('st', '')
dod = DynOptionDescription('dod', '', [st], callback=return_list)
od = OptionDescription('od', '', [dod])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
owner = cfg.cfgimpl_get_settings().getowner()
stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
assert cfg.od.dodval1.stval1 is None
assert cfg.od.dodval2.stval2 is None
assert cfg.getowner(stval1) == owners.default
assert cfg.getowner(stval2) == owners.default
cfg.od.dodval1.stval1 = 'yes'
assert cfg.od.dodval1.stval1 == 'yes'
assert cfg.od.dodval2.stval2 is None
assert cfg.getowner(stval1) == owner
assert cfg.getowner(stval2) == owners.default
cfg.od.dodval2.stval2 = 'no'
assert cfg.od.dodval1.stval1 == 'yes'
assert cfg.od.dodval2.stval2 == 'no'
assert cfg.getowner(st) == owners.default
assert cfg.getowner(stval1) == owner
assert cfg.getowner(stval2) == owner
def test_del_dyndescription():
st = StrOption('st', '')
dod = DynOptionDescription('dod', '', [st], callback=return_list)
od = OptionDescription('od', '', [dod])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
owner = cfg.cfgimpl_get_settings().getowner()
stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
assert cfg.od.dodval1.stval1 is None
assert cfg.od.dodval2.stval2 is None
cfg.od.dodval1.stval1 = 'yes'
assert cfg.getowner(stval1) == owner
del(cfg.od.dodval1.stval1)
assert cfg.getowner(stval1) == owners.default
def test_multi_dyndescription():
st = StrOption('st', '', multi=True)
dod = DynOptionDescription('dod', '', [st], callback=return_list)
od = OptionDescription('od', '', [dod])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
owner = cfg.cfgimpl_get_settings().getowner()
stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
assert cfg.od.dodval1.stval1 == []
assert cfg.od.dodval2.stval2 == []
assert cfg.getowner(stval1) == owners.default
assert cfg.getowner(stval2) == owners.default
cfg.od.dodval1.stval1.append('yes')
assert cfg.od.dodval1.stval1 == ['yes']
assert cfg.od.dodval2.stval2 == []
assert cfg.getowner(stval1) == owner
assert cfg.getowner(stval2) == owners.default
cfg.od.dodval2.stval2 = ['no']
assert cfg.od.dodval1.stval1 == ['yes']
assert cfg.od.dodval2.stval2 == ['no']
assert cfg.getowner(st) == owners.default
assert cfg.getowner(stval1) == owner
assert cfg.getowner(stval2) == owner
cfg.od.dodval1.stval1.append('yes')
assert cfg.od.dodval1.stval1 == ['yes', 'yes']
cfg.od.dodval1.stval1.pop(0)
assert cfg.od.dodval1.stval1 == ['yes']
def test_prop_dyndescription():
st = StrOption('st', '', properties=('test',))
dod = DynOptionDescription('dod', '', [st], callback=return_list)
od = OptionDescription('od', '', [dod])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
dodval1 = cfg.unwrap_from_path('od.dodval1')
dodval2 = cfg.unwrap_from_path('od.dodval2')
assert str(cfg.cfgimpl_get_settings()[stval1]) == str(['test'])
assert str(cfg.cfgimpl_get_settings()[stval2]) == str(['test'])
cfg.cfgimpl_get_settings()[stval2].append('test2')
assert str(cfg.cfgimpl_get_settings()[stval1]) == str(['test'])
assert str(cfg.cfgimpl_get_settings()[stval2]) == str(['test', 'test2'])
cfg.cfgimpl_get_settings()[stval1].remove('test')
assert str(cfg.cfgimpl_get_settings()[stval1]) == str([])
#
assert str(cfg.cfgimpl_get_settings()[dodval1]) == str([])
assert str(cfg.cfgimpl_get_settings()[dodval2]) == str([])
cfg.cfgimpl_get_settings()[dodval1].append('test1')
assert str(cfg.cfgimpl_get_settings()[dodval1]) == str(['test1'])
assert str(cfg.cfgimpl_get_settings()[dodval2]) == str([])
cfg.cfgimpl_get_settings()[dodval1].remove('test1')
assert str(cfg.cfgimpl_get_settings()[dodval1]) == str([])
assert str(cfg.cfgimpl_get_settings()[dodval2]) == str([])
def test_callback_dyndescription():
st = StrOption('st', '', callback=return_dynval)
dod = DynOptionDescription('dod', '', [st], callback=return_list)
od = OptionDescription('od', '', [dod])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
owner = cfg.cfgimpl_get_settings().getowner()
stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
assert cfg.od.dodval1.stval1 == 'val'
assert cfg.od.dodval2.stval2 == 'val'
assert cfg.getowner(stval1) == owners.default
assert cfg.getowner(stval2) == owners.default
cfg.od.dodval1.stval1 = 'val2'
assert cfg.od.dodval1.stval1 == 'val2'
assert cfg.od.dodval2.stval2 == 'val'
assert cfg.getowner(stval1) == owner
assert cfg.getowner(stval2) == owners.default
del(cfg.od.dodval1.stval1)
assert cfg.od.dodval1.stval1 == 'val'
assert cfg.od.dodval2.stval2 == 'val'
assert cfg.getowner(stval1) == owners.default
assert cfg.getowner(stval2) == owners.default
def test_callback_list_dyndescription():
st = StrOption('st', '', callback=return_list2, multi=True)
dod = DynOptionDescription('dod', '', [st], callback=return_list)
od = OptionDescription('od', '', [dod])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
owner = cfg.cfgimpl_get_settings().getowner()
stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
assert cfg.od.dodval1.stval1 == ['val1', 'val2']
assert cfg.od.dodval2.stval2 == ['val2', 'val2']
assert cfg.getowner(stval1) == owners.default
assert cfg.getowner(stval2) == owners.default
cfg.od.dodval1.stval1 = ['val3', 'val2']
assert cfg.od.dodval1.stval1 == ['val3', 'val2']
assert cfg.od.dodval2.stval2 == ['val2', 'val2']
assert cfg.getowner(stval1) == owner
assert cfg.getowner(stval2) == owners.default
def test_mandatory_dyndescription():
st = StrOption('st', '', properties=('mandatory',))
dod = DynOptionDescription('dod', '', [st], callback=return_list)
od = OptionDescription('od', '', [dod])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
cfg.read_only()
raises(PropertiesOptionError, "cfg.od.dodval1.stval1")
raises(PropertiesOptionError, "cfg.od.dodval2.stval2")
cfg.read_write()
cfg.od.dodval1.stval1 = 'val'
cfg.read_only()
assert cfg.od.dodval1.stval1 == 'val'
raises(PropertiesOptionError, "cfg.od.dodval2.stval2")
cfg.read_write()
del(cfg.od.dodval1.stval1)
cfg.read_only()
raises(PropertiesOptionError, "cfg.od.dodval1.stval1")
assert cfg.cfgimpl_get_values().mandatory_warnings() == ['od.dodval1.stval1', 'od.dodval2.stval2']
def test_build_dyndescription_context():
val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
st = StrOption('st', '')
dod = DynOptionDescription('dod', '', [st], callback=return_list, callback_params={'': ((val1, False),)})
od = OptionDescription('od', '', [dod, val1])
cfg = Config(od)
assert str(cfg) == """[dodval1]
[dodval2]
val1 = ['val1', 'val2']"""
assert str(cfg.dodval1) == "stval1 = None"
assert str(cfg.dodval2) == "stval2 = None"
cfg.unwrap_from_path('dodval2')
def test_subpath_dyndescription_context():
val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
st = StrOption('st', '')
dod = DynOptionDescription('dod', '', [st], callback=return_list, callback_params={'': ((val1, False),)})
od = OptionDescription('od', '', [dod, val1])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
assert str(cfg) == "[od]"
assert str(cfg.od) == """[dodval1]
[dodval2]
val1 = ['val1', 'val2']"""
assert str(cfg.od.dodval1) == "stval1 = None"
assert str(cfg.od.dodval2) == "stval2 = None"
def test_list_dyndescription_context():
val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
st = StrOption('st', '')
dod = DynOptionDescription('dod', '', [st], callback=return_list, callback_params={'': ((val1, False),)})
od = OptionDescription('od', '', [dod, val1])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
assert cfg.od.dodval1.stval1 is None
assert cfg.od.dodval2.stval2 is None
raises(AttributeError, "cfg.od.dodval3")
def test_mod_dyndescription_context():
val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
st = StrOption('st', '')
dod = DynOptionDescription('dod', '', [st], callback=return_list, callback_params={'': ((val1, False),)})
od = OptionDescription('od', '', [dod, val1])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
owner = cfg.cfgimpl_get_settings().getowner()
stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
assert cfg.od.dodval1.stval1 is None
assert cfg.od.dodval2.stval2 is None
assert cfg.getowner(stval1) == owners.default
assert cfg.getowner(stval2) == owners.default
cfg.od.dodval1.stval1 = 'yes'
assert cfg.od.dodval1.stval1 == 'yes'
assert cfg.od.dodval2.stval2 is None
assert cfg.getowner(stval1) == owner
assert cfg.getowner(stval2) == owners.default
cfg.od.dodval2.stval2 = 'no'
assert cfg.od.dodval1.stval1 == 'yes'
assert cfg.od.dodval2.stval2 == 'no'
assert cfg.getowner(st) == owners.default
assert cfg.getowner(stval1) == owner
assert cfg.getowner(stval2) == owner
def test_del_dyndescription_context():
val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
st = StrOption('st', '')
dod = DynOptionDescription('dod', '', [st], callback=return_list, callback_params={'': ((val1, False),)})
od = OptionDescription('od', '', [dod, val1])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
owner = cfg.cfgimpl_get_settings().getowner()
stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
assert cfg.od.dodval1.stval1 is None
assert cfg.od.dodval2.stval2 is None
cfg.od.dodval1.stval1 = 'yes'
assert cfg.getowner(stval1) == owner
del(cfg.od.dodval1.stval1)
assert cfg.getowner(stval1) == owners.default
def test_multi_dyndescription_context():
val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
st = StrOption('st', '', multi=True)
dod = DynOptionDescription('dod', '', [st], callback=return_list, callback_params={'': ((val1, False),)})
od = OptionDescription('od', '', [dod, val1])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
owner = cfg.cfgimpl_get_settings().getowner()
stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
assert cfg.od.dodval1.stval1 == []
assert cfg.od.dodval2.stval2 == []
assert cfg.getowner(stval1) == owners.default
assert cfg.getowner(stval2) == owners.default
cfg.od.dodval1.stval1.append('yes')
assert cfg.od.dodval1.stval1 == ['yes']
assert cfg.od.dodval2.stval2 == []
assert cfg.getowner(stval1) == owner
assert cfg.getowner(stval2) == owners.default
cfg.od.dodval2.stval2 = ['no']
assert cfg.od.dodval1.stval1 == ['yes']
assert cfg.od.dodval2.stval2 == ['no']
assert cfg.getowner(st) == owners.default
assert cfg.getowner(stval1) == owner
assert cfg.getowner(stval2) == owner
cfg.od.dodval1.stval1.append('yes')
assert cfg.od.dodval1.stval1 == ['yes', 'yes']
cfg.od.dodval1.stval1.pop(0)
assert cfg.od.dodval1.stval1 == ['yes']
def test_prop_dyndescription_context():
val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
st = StrOption('st', '', properties=('test',))
dod = DynOptionDescription('dod', '', [st], callback=return_list, callback_params={'': ((val1, False),)})
od = OptionDescription('od', '', [dod, val1])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
assert str(cfg.cfgimpl_get_settings()[stval1]) == str(['test'])
assert str(cfg.cfgimpl_get_settings()[stval2]) == str(['test'])
cfg.cfgimpl_get_settings()[stval2].append('test2')
assert str(cfg.cfgimpl_get_settings()[stval1]) == str(['test'])
assert str(cfg.cfgimpl_get_settings()[stval2]) == str(['test', 'test2'])
cfg.cfgimpl_get_settings()[stval1].remove('test')
assert str(cfg.cfgimpl_get_settings()[stval1]) == str([])
def test_callback_dyndescription_context():
val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
st = StrOption('st', '', callback=return_dynval)
dod = DynOptionDescription('dod', '', [st], callback=return_list)
od = OptionDescription('od', '', [dod, val1])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
owner = cfg.cfgimpl_get_settings().getowner()
stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
assert cfg.od.dodval1.stval1 == 'val'
assert cfg.od.dodval2.stval2 == 'val'
assert cfg.getowner(stval1) == owners.default
assert cfg.getowner(stval2) == owners.default
cfg.od.dodval1.stval1 = 'val2'
assert cfg.od.dodval1.stval1 == 'val2'
assert cfg.od.dodval2.stval2 == 'val'
assert cfg.getowner(stval1) == owner
assert cfg.getowner(stval2) == owners.default
del(cfg.od.dodval1.stval1)
assert cfg.od.dodval1.stval1 == 'val'
assert cfg.od.dodval2.stval2 == 'val'
assert cfg.getowner(stval1) == owners.default
assert cfg.getowner(stval2) == owners.default
def test_mandatory_dyndescription_context():
val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
st = StrOption('st', '', properties=('mandatory',))
dod = DynOptionDescription('dod', '', [st], callback=return_list, callback_params={'': ((val1, False),)})
od = OptionDescription('od', '', [dod, val1])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
cfg.read_only()
raises(PropertiesOptionError, "cfg.od.dodval1.stval1")
raises(PropertiesOptionError, "cfg.od.dodval2.stval2")
cfg.read_write()
cfg.od.dodval1.stval1 = 'val'
cfg.read_only()
assert cfg.od.dodval1.stval1 == 'val'
raises(PropertiesOptionError, "cfg.od.dodval2.stval2")
cfg.read_write()
del(cfg.od.dodval1.stval1)
cfg.read_only()
raises(PropertiesOptionError, "cfg.od.dodval1.stval1")
assert cfg.cfgimpl_get_values().mandatory_warnings() == ['od.dodval1.stval1', 'od.dodval2.stval2']
def test_increase_dyndescription_context():
val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
st = StrOption('st', '', properties=('mandatory',))
dod = DynOptionDescription('dod', '', [st], callback=return_list, callback_params={'': ((val1, False),)})
od = OptionDescription('od', '', [dod, val1])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
cfg.read_write()
assert cfg.od.dodval1.stval1 is None
assert cfg.od.dodval2.stval2 is None
raises(AttributeError, "cfg.od.dodval3")
cfg.od.val1 = ['val1', 'val2', 'val3']
assert cfg.od.dodval1.stval1 is None
assert cfg.od.dodval2.stval2 is None
assert cfg.od.dodval3.stval3 is None
def test_decrease_dyndescription_context():
val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
st = StrOption('st', '', properties=('mandatory',))
dod = DynOptionDescription('dod', '', [st], callback=return_list, callback_params={'': ((val1, False),)})
od = OptionDescription('od', '', [dod, val1])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
owner = cfg.cfgimpl_get_settings().getowner()
stval1 = cfg.unwrap_from_path('od.dodval1.stval1')
stval2 = cfg.unwrap_from_path('od.dodval2.stval2')
cfg.read_write()
assert cfg.od.dodval1.stval1 is None
assert cfg.od.dodval2.stval2 is None
cfg.od.dodval2.stval2 = 'yes'
assert cfg.od.dodval1.stval1 is None
assert cfg.od.dodval2.stval2 == 'yes'
assert cfg.getowner(stval1) == owners.default
assert cfg.getowner(stval2) == owner
raises(AttributeError, "cfg.od.dodval3")
cfg.od.val1 = ['val1']
assert cfg.od.dodval1.stval1 is None
raises(AttributeError, "cfg.od.dodval2")
raises(AttributeError, "cfg.od.dodval3")
assert cfg.getowner(stval1) == owners.default
#FIXME
# raises(AttributeError, "cfg.getowner(stval2)")
raises(AttributeError, "cfg.unwrap_from_path('od.dodval2.stval2')")
def test_requires_dyndescription():
boolean = BoolOption('boolean', '', True)
st = StrOption('st', '', requires=[{'option': boolean, 'expected': False,
'action': 'disabled'}])
dod = DynOptionDescription('dod', '', [st], callback=return_list)
od = OptionDescription('od', '', [dod])
od2 = OptionDescription('od', '', [od, boolean])
cfg = Config(od2)
cfg.read_write()
assert cfg.od.dodval1.stval1 is None
assert cfg.od.dodval2.stval2 is None
#
cfg.boolean = False
props = []
try:
cfg.od.dodval1.stval1
except PropertiesOptionError as err:
props = err.proptype
assert props == ['disabled']
props = []
try:
cfg.od.dodval2.stval2
except PropertiesOptionError as err:
props = err.proptype
assert props == ['disabled']
#
cfg.boolean = True
assert cfg.od.dodval1.stval1 is None
assert cfg.od.dodval2.stval2 is None
#transitive
cfg.cfgimpl_get_settings()[boolean].append('disabled')
props = []
try:
cfg.od.dodval1.stval1
except PropertiesOptionError as err:
props = err.proptype
assert props == ['disabled']
props = []
try:
cfg.od.dodval2.stval2
except PropertiesOptionError as err:
props = err.proptype
assert props == ['disabled']
def test_requires_dyndescription2():
boolean = BoolOption('boolean', '', True)
st = StrOption('st', '')
dod = DynOptionDescription('dod', '', [st], callback=return_list,
requires=[{'option': boolean, 'expected': False,
'action': 'disabled'}])
od = OptionDescription('od', '', [dod])
od2 = OptionDescription('od', '', [od, boolean])
cfg = Config(od2)
cfg.read_write()
assert cfg.od.dodval1.stval1 is None
assert cfg.od.dodval2.stval2 is None
#
cfg.boolean = False
props = []
try:
cfg.od.dodval1.stval1
except PropertiesOptionError as err:
props = err.proptype
assert props == ['disabled']
props = []
try:
cfg.od.dodval2.stval2
except PropertiesOptionError as err:
props = err.proptype
assert props == ['disabled']
#
cfg.boolean = True
assert cfg.od.dodval1.stval1 is None
assert cfg.od.dodval2.stval2 is None
#transitive
cfg.cfgimpl_get_settings()[boolean].append('disabled')
props = []
try:
cfg.od.dodval1.stval1
except PropertiesOptionError as err:
props = err.proptype
assert props == ['disabled']
props = []
try:
cfg.od.dodval2.stval2
except PropertiesOptionError as err:
props = err.proptype
assert props == ['disabled']
def test_validator_dyndescription():
val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
st = StrOption('st', '', validator=return_true, validator_params={'': ('yes',)}, default='val')
dod = DynOptionDescription('dod', '', [st], callback=return_list)
od = OptionDescription('od', '', [dod, val1])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
assert cfg.od.dodval1.stval1 == 'val'
raises(ValueError, "cfg.od.dodval1.stval1 = 'no'")
cfg.od.dodval1.stval1 = 'val'
def test_makedict_dyndescription_context():
val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
st = StrOption('st', '')
dod = DynOptionDescription('dod', '', [st], callback=return_list)
od = OptionDescription('od', '', [dod, val1])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
cfg.od.dodval1.stval1 = 'yes'
assert cfg.make_dict() == {'od.val1': ['val1', 'val2'], 'od.dodval1.stval1': 'yes', 'od.dodval2.stval2': None}
assert cfg.make_dict(flatten=True) == {'val1': ['val1', 'val2'], 'stval1': 'yes', 'stval2': None}
assert cfg.make_dict(withoption='stval1') == {'od.dodval1.stval1': 'yes'}
assert cfg.od.make_dict(withoption='stval1') == {'dodval1.stval1': 'yes'}
assert cfg.od.dodval1.make_dict(withoption='stval1') == {'stval1': 'yes'}
def test_find_dyndescription_context():
val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
st = StrOption('st', '')
dod = DynOptionDescription('dod', '', [st], callback=return_list)
od = OptionDescription('od', '', [dod, val1])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
cfg.od.dodval1.stval1 = 'yes'
assert cfg.find_first(byname='stval1', type_='value') == "yes"
assert isinstance(cfg.find_first(byname='stval1', type_='option'), DynSymLinkOption)
assert cfg.find(bytype=StrOption, type_='path') == ['od.dodval1.stval1', 'od.dodval2.stval2', 'od.val1']
opts = cfg.find(byvalue='yes')
assert len(opts) == 1
assert isinstance(opts[0], DynSymLinkOption)
assert opts[0].impl_getname() == 'stval1'
def test_iter_all_dyndescription_context():
val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
st = StrOption('st', '')
dod = DynOptionDescription('dod', '', [st], callback=return_list)
od = OptionDescription('od', '', [dod, val1])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
for it in cfg.iter_all():
assert it[0] == 'od'
assert str(it[1]) == str(cfg.od)
#
list_od = []
for it in cfg.od.iter_all():
list_od.append(it[0])
assert list_od == ['dodval1', 'dodval2', 'val1']
#
list_od = []
for it in cfg.od.dodval1:
list_od.append(it[0])
assert list_od == ['stval1']
def test_information_dyndescription_context():
val1 = StrOption('val1', '', ['val1', 'val2'], multi=True)
st = StrOption('st', '')
dod = DynOptionDescription('dod', '', [st], callback=return_list)
od = OptionDescription('od', '', [dod, val1])
od2 = OptionDescription('od', '', [od])
dod.impl_set_information('testod', 'val1')
st.impl_set_information('testst', 'val2')
cfg = Config(od2)
cfg.impl_set_information('testcfgod', 'val3')
assert dod.impl_get_information('testod') == 'val1'
assert st.impl_get_information('testst') == 'val2'
assert cfg.impl_get_information('testcfgod') == 'val3'
def test_consistency_dyndescription():
st = StrOption('st', '')
st2 = StrOption('st2', '')
dod = DynOptionDescription('dod', '', [st, st2], callback=return_list)
od = OptionDescription('od', '', [dod])
st.impl_add_consistency('not_equal', st2)
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
cfg.od.dodval1.stval1 = 'yes'
raises(ValueError, "cfg.od.dodval1.st2val1 = 'yes'")
cfg.od.dodval2.stval2 = 'yes'
raises(ValueError, "cfg.od.dodval2.st2val2 = 'yes'")
raises(ValueError, "cfg.od.dodval1.st2val1 = 'yes'")
del(cfg.od.dodval2.stval2)
raises(ValueError, "cfg.od.dodval1.st2val1 = 'yes'")
cfg.od.dodval2.st2val2 = 'yes'
raises(ValueError, "cfg.od.dodval2.stval2 = 'yes'")
def test_consistency_external_dyndescription():
st = StrOption('st', '')
st1 = StrOption('st1', '')
st2 = StrOption('st2', '')
dod = DynOptionDescription('dod', '', [st1, st2], callback=return_list)
od = OptionDescription('od', '', [dod, st])
raises(ConfigError, "st.impl_add_consistency('not_equal', st2)")
def test_consistency_notsame_dyndescription():
st1 = StrOption('st1', '')
st2 = StrOption('st2', '')
dod = DynOptionDescription('dod', '', [st1, st2], callback=return_list)
tst1 = StrOption('tst1', '')
tst2 = StrOption('tst2', '')
tdod = DynOptionDescription('tdod', '', [tst1, tst2], callback=return_list)
od = OptionDescription('od', '', [dod, tdod])
raises(ConfigError, "st1.impl_add_consistency('not_equal', tst1)")
def test_all_dyndescription():
st = StrOption('st', '')
ip = IPOption('ip', '')
network = NetworkOption('network', '')
netmask = NetmaskOption('netmask', '')
ch = ChoiceOption('ch', '', ('val1', 'val2', 'val3'))
ch1 = ChoiceOption('ch1', '', return_list)
boo = BoolOption('boo', '')
intr = IntOption('intr', '')
floa = FloatOption('floa', '')
uni = UnicodeOption('uni', '')
port = PortOption('port', '')
broad = BroadcastOption('broad', '')
domain = DomainnameOption('domain', '')
email = EmailOption('email', '')
url = URLOption('url', '')
username = UsernameOption('username', '')
filename = FilenameOption('filename', '')
dod = DynOptionDescription('dod', '', [st, ip, network, netmask, ch, ch1,
boo, intr, floa, uni, port, broad,
domain, email, url, username,
filename], callback=return_list)
od = OptionDescription('od', '', [dod])
cfg = Config(od)
assert cfg.dodval1.stval1 is None
assert cfg.dodval1.ipval1 is None
assert cfg.dodval1.networkval1 is None
assert cfg.dodval1.netmaskval1 is None
assert cfg.dodval1.chval1 is None
assert cfg.dodval1.ch1val1 is None
assert cfg.dodval1.booval1 is None
assert cfg.dodval1.intrval1 is None
assert cfg.dodval1.floaval1 is None
assert cfg.dodval1.unival1 is None
assert cfg.dodval1.portval1 is None
assert cfg.dodval1.broadval1 is None
assert cfg.dodval1.domainval1 is None
assert cfg.dodval1.emailval1 is None
assert cfg.dodval1.urlval1 is None
assert cfg.dodval1.usernameval1 is None
assert cfg.dodval1.filenameval1 is None
#
cfg.dodval1.stval1 = "no"
cfg.dodval1.ipval1 = "1.1.1.1"
cfg.dodval1.networkval1 = "1.1.1.0"
cfg.dodval1.netmaskval1 = "255.255.255.0"
cfg.dodval1.chval1 = "val1"
cfg.dodval1.ch1val1 = "val2"
cfg.dodval1.booval1 = True
cfg.dodval1.intrval1 = 1
cfg.dodval1.floaval1 = 0.1
cfg.dodval1.unival1 = u"no"
cfg.dodval1.portval1 = 80
cfg.dodval1.broadval1 = "1.1.1.255"
cfg.dodval1.domainval1 = "test.com"
cfg.dodval1.emailval1 = "test@test.com"
cfg.dodval1.urlval1 = "http://test.com"
cfg.dodval1.usernameval1 = "user1"
cfg.dodval1.filenameval1 = "/tmp"
assert cfg.dodval1.stval1 == "no"
assert cfg.dodval1.ipval1 == "1.1.1.1"
assert cfg.dodval1.networkval1 == "1.1.1.0"
assert cfg.dodval1.netmaskval1 == "255.255.255.0"
assert cfg.dodval1.chval1 == "val1"
assert cfg.dodval1.ch1val1 == "val2"
assert cfg.dodval1.booval1 is True
assert cfg.dodval1.intrval1 == 1
assert cfg.dodval1.floaval1 == 0.1
assert cfg.dodval1.unival1 == u"no"
assert cfg.dodval1.portval1 == 80
assert cfg.dodval1.broadval1 == "1.1.1.255"
assert cfg.dodval1.domainval1 == "test.com"
assert cfg.dodval1.emailval1 == "test@test.com"
assert cfg.dodval1.urlval1 == "http://test.com"
assert cfg.dodval1.usernameval1 == "user1"
assert cfg.dodval1.filenameval1 == "/tmp"
#
assert cfg.dodval2.stval2 is None
assert cfg.dodval2.ipval2 is None
assert cfg.dodval2.networkval2 is None
assert cfg.dodval2.netmaskval2 is None
assert cfg.dodval2.chval2 is None
assert cfg.dodval2.ch1val2 is None
assert cfg.dodval2.booval2 is None
assert cfg.dodval2.intrval2 is None
assert cfg.dodval2.floaval2 is None
assert cfg.dodval2.unival2 is None
assert cfg.dodval2.portval2 is None
assert cfg.dodval2.broadval2 is None
assert cfg.dodval2.domainval2 is None
assert cfg.dodval2.emailval2 is None
assert cfg.dodval2.urlval2 is None
assert cfg.dodval2.usernameval2 is None
assert cfg.dodval2.filenameval2 is None
def test_consistency_ip_netmask_dyndescription():
a = IPOption('a', '')
b = NetmaskOption('b', '')
dod = DynOptionDescription('dod', '', [a, b], callback=return_list)
b.impl_add_consistency('ip_netmask', a)
od = OptionDescription('od', '', [dod])
c = Config(od)
c.dodval1.aval1 = '192.168.1.1'
c.dodval1.bval1 = '255.255.255.0'
c.dodval2.aval2 = '192.168.1.2'
c.dodval2.bval2 = '255.255.255.255'
c.dodval2.bval2 = '255.255.255.0'
def test_consistency_ip_in_network_dyndescription():
a = NetworkOption('a', '')
b = NetmaskOption('b', '')
c = IPOption('c', '')
dod = DynOptionDescription('dod', '', [a, b, c], callback=return_list)
c.impl_add_consistency('in_network', a, b)
od = OptionDescription('od', '', [dod])
cfg = Config(od)
cfg.dodval1.aval1 = '192.168.1.0'
cfg.dodval1.bval1 = '255.255.255.0'
cfg.dodval1.cval1 = '192.168.1.1'
def test_masterslaves_dyndescription():
st1 = StrOption('st1', "", multi=True)
st2 = StrOption('st2', "", multi=True)
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])
cfg = Config(od2)
owner = cfg.cfgimpl_get_settings().getowner()
st1val1 = cfg.unwrap_from_path('od.stval1.st1val1.st1val1')
st2val1 = cfg.unwrap_from_path('od.stval1.st1val1.st2val1')
st1val2 = cfg.unwrap_from_path('od.stval2.st1val2.st1val2')
st2val2 = cfg.unwrap_from_path('od.stval2.st1val2.st2val2')
assert cfg.make_dict() == {'od.stval1.st1val1.st2val1': [], 'od.stval2.st1val2.st2val2': [], 'od.stval2.st1val2.st1val2': [], 'od.stval1.st1val1.st1val1': []}
assert cfg.od.stval1.st1val1.st1val1 == []
assert cfg.od.stval1.st1val1.st2val1 == []
assert cfg.od.stval2.st1val2.st1val2 == []
assert cfg.od.stval2.st1val2.st2val2 == []
assert cfg.getowner(st1val1) == owners.default
assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owners.default
assert cfg.getowner(st2val2) == owners.default
#
cfg.od.stval1.st1val1.st1val1.append('yes')
assert cfg.make_dict() == {'od.stval1.st1val1.st2val1': [None], 'od.stval2.st1val2.st2val2': [], 'od.stval2.st1val2.st1val2': [], 'od.stval1.st1val1.st1val1': ['yes']}
assert cfg.od.stval1.st1val1.st1val1 == ['yes']
assert cfg.od.stval1.st1val1.st2val1 == [None]
assert cfg.od.stval2.st1val2.st1val2 == []
assert cfg.od.stval2.st1val2.st2val2 == []
assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owners.default
assert cfg.getowner(st2val2) == owners.default
#
cfg.od.stval1.st1val1.st1val1 = ['yes']
assert cfg.od.stval1.st1val1.st1val1 == ['yes']
assert cfg.od.stval1.st1val1.st2val1 == [None]
assert cfg.od.stval2.st1val2.st1val2 == []
assert cfg.od.stval2.st1val2.st2val2 == []
assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owners.default
assert cfg.getowner(st2val2) == owners.default
#
cfg.od.stval1.st1val1.st2val1 = ['no']
assert cfg.od.stval1.st1val1.st1val1 == ['yes']
assert cfg.od.stval1.st1val1.st2val1 == ['no']
assert cfg.od.stval2.st1val2.st1val2 == []
assert cfg.od.stval2.st1val2.st2val2 == []
assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owner
assert cfg.getowner(st2val2) == owners.default
#
cfg.od.stval1.st1val1.st1val1.pop(0)
assert cfg.od.stval1.st1val1.st1val1 == []
assert cfg.od.stval1.st1val1.st2val1 == []
assert cfg.od.stval2.st1val2.st1val2 == []
assert cfg.od.stval2.st1val2.st2val2 == []
assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owner
assert cfg.getowner(st2val2) == owners.default
#
cfg.od.stval1.st1val1.st1val1 = ['yes']
cfg.od.stval1.st1val1.st2val1 = ['yes']
assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st2val1) == owner
del(cfg.od.stval1.st1val1.st2val1)
assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owners.default
assert cfg.getowner(st2val2) == owners.default
#
cfg.od.stval1.st1val1.st1val1 = ['yes']
cfg.od.stval1.st1val1.st2val1 = ['yes']
del(cfg.od.stval1.st1val1.st1val1)
assert cfg.od.stval1.st1val1.st1val1 == []
assert cfg.od.stval1.st1val1.st2val1 == []
assert cfg.od.stval2.st1val2.st1val2 == []
assert cfg.od.stval2.st1val2.st2val2 == []
assert cfg.getowner(st1val1) == owners.default
assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owners.default
assert cfg.getowner(st2val2) == owners.default
def test_masterslaves_default_multi_dyndescription():
st1 = StrOption('st1', "", multi=True)
st2 = StrOption('st2', "", multi=True, default_multi='no')
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])
cfg = Config(od2)
owner = cfg.cfgimpl_get_settings().getowner()
st1val1 = cfg.unwrap_from_path('od.stval1.st1val1.st1val1')
st2val1 = cfg.unwrap_from_path('od.stval1.st1val1.st2val1')
st1val2 = cfg.unwrap_from_path('od.stval2.st1val2.st1val2')
st2val2 = cfg.unwrap_from_path('od.stval2.st1val2.st2val2')
assert cfg.od.stval1.st1val1.st1val1 == []
assert cfg.od.stval1.st1val1.st2val1 == []
assert cfg.od.stval2.st1val2.st1val2 == []
assert cfg.od.stval2.st1val2.st2val2 == []
assert cfg.getowner(st1val1) == owners.default
assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owners.default
assert cfg.getowner(st2val2) == owners.default
cfg.od.stval1.st1val1.st1val1.append('yes')
assert cfg.od.stval1.st1val1.st1val1 == ['yes']
assert cfg.od.stval1.st1val1.st2val1 == ['no']
assert cfg.od.stval2.st1val2.st1val2 == []
assert cfg.od.stval2.st1val2.st2val2 == []
assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owners.default
assert cfg.getowner(st2val2) == owners.default
def test_masterslaves_submulti_dyndescription():
st1 = StrOption('st1', "", multi=True)
st2 = StrOption('st2', "", multi=submulti)
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])
cfg = Config(od2)
owner = cfg.cfgimpl_get_settings().getowner()
st1val1 = cfg.unwrap_from_path('od.stval1.st1val1.st1val1')
st2val1 = cfg.unwrap_from_path('od.stval1.st1val1.st2val1')
st1val2 = cfg.unwrap_from_path('od.stval2.st1val2.st1val2')
st2val2 = cfg.unwrap_from_path('od.stval2.st1val2.st2val2')
assert cfg.od.stval1.st1val1.st1val1 == []
assert cfg.od.stval1.st1val1.st2val1 == []
assert cfg.od.stval2.st1val2.st1val2 == []
assert cfg.od.stval2.st1val2.st2val2 == []
assert cfg.getowner(st1val1) == owners.default
assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owners.default
assert cfg.getowner(st2val2) == owners.default
cfg.od.stval1.st1val1.st1val1.append('yes')
assert cfg.od.stval1.st1val1.st1val1 == ['yes']
assert cfg.od.stval1.st1val1.st2val1 == [[]]
assert cfg.od.stval2.st1val2.st1val2 == []
assert cfg.od.stval2.st1val2.st2val2 == []
assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owners.default
assert cfg.getowner(st2val2) == owners.default
#
cfg.od.stval1.st1val1.st2val1[0].append('no')
assert cfg.od.stval1.st1val1.st1val1 == ['yes']
assert cfg.od.stval1.st1val1.st2val1 == [['no']]
assert cfg.od.stval2.st1val2.st1val2 == []
assert cfg.od.stval2.st1val2.st2val2 == []
assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owner
assert cfg.getowner(st2val2) == owners.default
def test_masterslaves_consistency_ip_dyndescription():
a = NetworkOption('net', '', multi=True)
b = NetmaskOption('mask', '', multi=True)
c = BroadcastOption('broad', '', multi=True)
b.impl_add_consistency('network_netmask', a)
c.impl_add_consistency('broadcast', a, b)
dod = DynOptionDescription('net', '', [a, b, c], callback=return_list)
dod.impl_set_group_type(groups.master)
od = OptionDescription('od', '', [dod])
cfg = Config(od)
cfg.netval1.netval1 = ['192.168.1.0']
cfg.netval1.maskval1 = ['255.255.255.0']
cfg.netval1.broadval1 = ['192.168.1.255']
cfg.netval1.netval1 = ['192.168.1.0', '192.168.2.128']
cfg.netval1.maskval1 = ['255.255.255.0', '255.255.255.128']
cfg.netval1.broadval1 = ['192.168.1.255', '192.168.2.255']
cfg.netval1.broadval1[1] = '192.168.2.255'
#
assert cfg.netval1.netval1 == ['192.168.1.0', '192.168.2.128']
assert cfg.netval1.maskval1 == ['255.255.255.0', '255.255.255.128']
assert cfg.netval1.broadval1 == ['192.168.1.255', '192.168.2.255']
assert cfg.netval2.netval2 == []
assert cfg.netval2.maskval2 == []
assert cfg.netval2.broadval2 == []
def test_masterslaves_callback_dyndescription():
st1 = StrOption('st1', "", multi=True)
st2 = StrOption('st2', "", multi=True, callback=return_dynval, callback_params={'value': ((st1, 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])
cfg = Config(od2)
owner = cfg.cfgimpl_get_settings().getowner()
st1val1 = cfg.unwrap_from_path('od.stval1.st1val1.st1val1')
st2val1 = cfg.unwrap_from_path('od.stval1.st1val1.st2val1')
st1val2 = cfg.unwrap_from_path('od.stval2.st1val2.st1val2')
st2val2 = cfg.unwrap_from_path('od.stval2.st1val2.st2val2')
assert cfg.make_dict() == {'od.stval1.st1val1.st2val1': [], 'od.stval2.st1val2.st2val2': [], 'od.stval2.st1val2.st1val2': [], 'od.stval1.st1val1.st1val1': []}
assert cfg.od.stval1.st1val1.st1val1 == []
assert cfg.od.stval1.st1val1.st2val1 == []
assert cfg.od.stval2.st1val2.st1val2 == []
assert cfg.od.stval2.st1val2.st2val2 == []
assert cfg.getowner(st1val1) == owners.default
assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owners.default
assert cfg.getowner(st2val2) == owners.default
#
cfg.od.stval1.st1val1.st1val1.append('yes')
assert cfg.make_dict() == {'od.stval1.st1val1.st2val1': ['yes'], 'od.stval2.st1val2.st2val2': [], 'od.stval2.st1val2.st1val2': [], 'od.stval1.st1val1.st1val1': ['yes']}
assert cfg.od.stval1.st1val1.st1val1 == ['yes']
assert cfg.od.stval1.st1val1.st2val1 == ['yes']
assert cfg.od.stval2.st1val2.st1val2 == []
assert cfg.od.stval2.st1val2.st2val2 == []
assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owners.default
assert cfg.getowner(st2val2) == owners.default
#
cfg.od.stval1.st1val1.st2val1 = ['no']
assert cfg.od.stval1.st1val1.st1val1 == ['yes']
assert cfg.od.stval1.st1val1.st2val1 == ['no']
assert cfg.od.stval2.st1val2.st1val2 == []
assert cfg.od.stval2.st1val2.st2val2 == []
assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owner
assert cfg.getowner(st2val2) == owners.default
#
cfg.od.stval1.st1val1.st1val1.pop(0)
assert cfg.od.stval1.st1val1.st1val1 == []
assert cfg.od.stval1.st1val1.st2val1 == []
assert cfg.od.stval2.st1val2.st1val2 == []
assert cfg.od.stval2.st1val2.st2val2 == []
assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owner
assert cfg.getowner(st2val2) == owners.default
#
cfg.od.stval1.st1val1.st1val1 = ['yes']
cfg.od.stval1.st1val1.st2val1 = ['yes']
assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st2val1) == owner
del(cfg.od.stval1.st1val1.st2val1)
assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owners.default
assert cfg.getowner(st2val2) == owners.default
#
cfg.od.stval1.st1val1.st1val1 = ['yes']
cfg.od.stval1.st1val1.st2val1 = ['yes']
del(cfg.od.stval1.st1val1.st1val1)
assert cfg.od.stval1.st1val1.st1val1 == []
assert cfg.od.stval1.st1val1.st2val1 == []
assert cfg.od.stval2.st1val2.st1val2 == []
assert cfg.od.stval2.st1val2.st2val2 == []
assert cfg.getowner(st1val1) == owners.default
assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owners.default
assert cfg.getowner(st2val2) == owners.default
#
cfg.od.stval1.st1val1.st2val1 = []
cfg.od.stval1.st1val1.st1val1 = ['yes']
assert cfg.od.stval1.st1val1.st2val1 == ['yes']
def test_masterslaves_callback_value_dyndescription():
st1 = StrOption('st1', "", multi=True)
st2 = StrOption('st2', "", multi=True, callback=return_dynval, callback_params={'value': ('val',)})
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])
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[0] == 'val'
assert cfg.od.stval1.st1val1.st2val1 == ['val']
def test_masterslaves_callback_nomulti_dyndescription():
v1 = StrOption('v1', '', "val")
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 == ['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():
st1 = StrOption('st1', "", multi=True)
st2 = StrOption('st2', "", multi=True)
st3 = StrOption('st3', "", multi=True, callback=return_dynval, callback_params={'': ((st2, False),)})
stm = OptionDescription('st1', '', [st1, st2, st3])
stm.impl_set_group_type(groups.master)
st = DynOptionDescription('st', '', [stm], callback=return_list)
od = OptionDescription('od', '', [st])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
owner = cfg.cfgimpl_get_settings().getowner()
st1val1 = cfg.unwrap_from_path('od.stval1.st1val1.st1val1')
st2val1 = cfg.unwrap_from_path('od.stval1.st1val1.st2val1')
st3val1 = cfg.unwrap_from_path('od.stval1.st1val1.st3val1')
st1val2 = cfg.unwrap_from_path('od.stval2.st1val2.st1val2')
st2val2 = cfg.unwrap_from_path('od.stval2.st1val2.st2val2')
st3val2 = cfg.unwrap_from_path('od.stval2.st1val2.st3val2')
assert cfg.make_dict() == {'od.stval1.st1val1.st1val1': [],
'od.stval1.st1val1.st2val1': [],
'od.stval1.st1val1.st3val1': [],
'od.stval2.st1val2.st1val2': [],
'od.stval2.st1val2.st2val2': [],
'od.stval2.st1val2.st3val2': []}
assert cfg.od.stval1.st1val1.st1val1 == []
assert cfg.od.stval1.st1val1.st2val1 == []
assert cfg.od.stval1.st1val1.st3val1 == []
assert cfg.od.stval2.st1val2.st1val2 == []
assert cfg.od.stval2.st1val2.st2val2 == []
assert cfg.od.stval2.st1val2.st3val2 == []
assert cfg.getowner(st1val1) == owners.default
assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owners.default
assert cfg.getowner(st2val2) == owners.default
assert cfg.getowner(st3val1) == owners.default
assert cfg.getowner(st3val2) == owners.default
##
cfg.od.stval1.st1val1.st1val1.append('yes')
assert cfg.make_dict() == {'od.stval1.st1val1.st1val1': ['yes'],
'od.stval1.st1val1.st2val1': [None],
'od.stval1.st1val1.st3val1': [None],
'od.stval2.st1val2.st1val2': [],
'od.stval2.st1val2.st2val2': [],
'od.stval2.st1val2.st3val2': []}
assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owners.default
assert cfg.getowner(st2val2) == owners.default
assert cfg.getowner(st3val1) == owners.default
assert cfg.getowner(st3val2) == owners.default
#
cfg.od.stval1.st1val1.st2val1[0] = 'yes'
assert cfg.make_dict() == {'od.stval1.st1val1.st1val1': ['yes'],
'od.stval1.st1val1.st2val1': ['yes'],
'od.stval1.st1val1.st3val1': ['yes'],
'od.stval2.st1val2.st1val2': [],
'od.stval2.st1val2.st2val2': [],
'od.stval2.st1val2.st3val2': []}
assert cfg.getowner(st1val1) == owner
assert cfg.getowner(st1val2) == owners.default
assert cfg.getowner(st2val1) == owner
assert cfg.getowner(st2val2) == owners.default
assert cfg.getowner(st3val1) == owners.default
assert cfg.getowner(st3val2) == owners.default
def test_state_config():
a = IPOption('a', '')
b = NetmaskOption('b', '')
dod1 = DynOptionDescription('dod1', '', [a, b], callback=return_list)
b.impl_add_consistency('ip_netmask', a)
od1 = OptionDescription('od1', '', [dod1])
st1 = StrOption('st1', "", multi=True)
st2 = StrOption('st2', "", multi=True)
st3 = StrOption('st3', "", multi=True, callback=return_dynval, callback_params={'': ((st2, False),)})
stm = OptionDescription('st1', '', [st1, st2, st3])
stm.impl_set_group_type(groups.master)
st = DynOptionDescription('st', '', [stm], callback=return_list)
od = OptionDescription('od', '', [st])
od2 = OptionDescription('od', '', [od, od1])
try:
cfg = Config(od2, persistent=True, session_id='29090938')
except ValueError:
cfg = Config(od2, session_id='29090938')
cfg._impl_test = True
a = dumps(cfg)
q = loads(a)
_diff_opts(cfg.cfgimpl_get_description(), q.cfgimpl_get_description())
_diff_conf(cfg, q)
try:
delete_session('config', '29090938')
except ConfigError:
pass
def test_invalid_conflict_dyndescription():
st = StrOption('st', '')
dod = DynOptionDescription('dod', '', [st], callback=return_list)
dodinvalid = StrOption('dodinvalid', '')
raises(ConflictError, "OptionDescription('od', '', [dod, dodinvalid])")
def test_invalid_subod_dyndescription():
st2 = StrOption('st2', '')
od1 = OptionDescription('od1', '', [st2])
raises(ConfigError, "DynOptionDescription('dod', '', [od1], callback=return_list)")
def test_invalid_subdynod_dyndescription():
st2 = StrOption('st2', '')
od1 = DynOptionDescription('od1', '', [st2], callback=return_list)
raises(ConfigError, "DynOptionDescription('dod', '', [od1], callback=return_list)")
def test_invalid_symlink_dyndescription():
st = StrOption('st', '')
st2 = SymLinkOption('st2', st)
raises(ConfigError, "DynOptionDescription('dod', '', [st, st2], callback=return_list)")
def test_nocallback_dyndescription():
st = StrOption('st', '')
st2 = StrOption('st2', st)
raises(ConfigError, "DynOptionDescription('dod', '', [st, st2])")
def test_invalid_samevalue_dyndescription():
def return_same_list():
return ['val1', 'val1']
st = StrOption('st', '')
dod = DynOptionDescription('dod', '', [st], callback=return_same_list)
od = OptionDescription('od', '', [dod])
cfg = Config(od)
raises(ConfigError, "print cfg")
def test_invalid_name_dyndescription():
def return_same_list():
return ['---', ' ']
st = StrOption('st', '')
dod = DynOptionDescription('dod', '', [st], callback=return_same_list)
od = OptionDescription('od', '', [dod])
cfg = Config(od)
raises(ValueError, "print cfg")

View File

@ -46,9 +46,12 @@ def a_func():
def test_option_valid_name():
IntOption('test', '')
raises(ValueError, 'IntOption(1, "")')
raises(ValueError, 'IntOption("1test", "")')
IntOption("test1", "")
raises(ValueError, 'IntOption("impl_test", "")')
raises(ValueError, 'IntOption("_test", "")')
raises(ValueError, 'IntOption("unwrap_from_path", "")')
raises(ValueError, 'IntOption(" ", "")')
def test_option_with_callback():

View File

@ -51,30 +51,6 @@ def is_config(config, **kwargs):
return 'no'
def make_description():
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
gcdummy = BoolOption('dummy', 'dummy', default=False)
objspaceoption = ChoiceOption('objspace', 'Object space',
('std', 'thunk'), 'std')
booloption = BoolOption('bool', 'Test boolean option', default=True)
intoption = IntOption('int', 'Test int option', default=0)
intoption2 = IntOption('int', 'Test int option', default=0)
floatoption = FloatOption('float', 'Test float option', default=2.3)
stroption = StrOption('str', 'Test string option', default="abc")
boolop = BoolOption('boolop', 'Test boolean option op', default=True)
wantref_option = BoolOption('wantref', 'Test requires', default=False,
requires=({'option': boolop, 'expected': True, 'action': 'hidden'},))
wantframework_option = BoolOption('wantframework', 'Test requires',
default=False,
requires=({'option': boolop, 'expected': True, 'action': 'hidden'},))
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption, intoption2])
descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
wantref_option, stroption,
wantframework_option,
intoption, boolop])
return descr
def make_description_duplicates():
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
## dummy 1
@ -929,3 +905,26 @@ def test_callback_multi_list_params_key():
cfg = Config(maconfig)
cfg.read_write()
assert cfg.val2.val2 == ['val', 'val']
def test_masterslaves_callback_description():
st1 = StrOption('st1', "", multi=True)
st2 = StrOption('st2', "", multi=True, callback=return_value, callback_params={'': ((st1, False),)})
stm = OptionDescription('st1', '', [st1, st2])
stm.impl_set_group_type(groups.master)
st = OptionDescription('st', '', [stm])
od = OptionDescription('od', '', [st])
od2 = OptionDescription('od', '', [od])
cfg = Config(od2)
owner = cfg.cfgimpl_get_settings().getowner()
st1 = cfg.unwrap_from_path('od.st.st1.st1')
st2 = cfg.unwrap_from_path('od.st.st1.st2')
assert cfg.od.st.st1.st1 == []
assert cfg.od.st.st1.st2 == []
assert cfg.getowner(st1) == owners.default
assert cfg.getowner(st2) == owners.default
##
cfg.od.st.st1.st1.append('yes')
assert cfg.od.st.st1.st1 == ['yes']
assert cfg.od.st.st1.st2 == ['yes']
assert cfg.getowner(st1) == owner

View File

@ -1,9 +1,10 @@
import autopath
from tiramisu.option import BoolOption, UnicodeOption, SymLinkOption, \
IntOption, OptionDescription
IntOption, IPOption, NetmaskOption, StrOption, OptionDescription, \
DynOptionDescription
from tiramisu.config import Config, GroupConfig, MetaConfig
from tiramisu.setting import owners
from tiramisu.setting import groups, owners
from tiramisu.storage import delete_session
from tiramisu.error import ConfigError
from pickle import dumps, loads
@ -93,10 +94,35 @@ def _diff_opt(opt1, opt2):
assert val1[key][idx] == val2[key][idx]
else:
assert val1 == val2
elif attr == '_master_slaves':
assert val1.master.impl_getname() == val2.master.impl_getname()
sval1 = [opt.impl_getname() for opt in val1.slaves]
sval2 = [opt.impl_getname() for opt in val2.slaves]
assert sval1 == sval2
elif attr == '_subdyn':
try:
assert val1.impl_getname() == val2.impl_getname()
except AttributeError:
assert val1 == val2
else:
assert val1 == val2
def _diff_opts(opt1, opt2):
_diff_opt(opt1, opt2)
if isinstance(opt1, OptionDescription) or isinstance(opt1, DynOptionDescription):
children1 = set([opt.impl_getname() for opt in opt1._impl_getchildren(dyn=False)])
children2 = set([opt.impl_getname() for opt in opt2._impl_getchildren(dyn=False)])
diff1 = children1 - children2
diff2 = children2 - children1
if diff1 != set():
raise Exception('more attribute in opt1 {0}'.format(list(diff1)))
if diff2 != set():
raise Exception('more attribute in opt2 {0}'.format(list(diff2)))
for child in children1:
_diff_opts(opt1._getattr(child, dyn=False), opt2._getattr(child, dyn=False))
def _diff_conf(cfg1, cfg2):
attr1 = set(_get_slots(cfg1))
attr2 = set(_get_slots(cfg2))
@ -148,11 +174,7 @@ def test_diff_opt():
a = dumps(o1)
q = loads(a)
_diff_opt(o1, q)
_diff_opt(o1.o, q.o)
_diff_opt(o1.o.b, q.o.b)
_diff_opt(o1.o.u, q.o.u)
_diff_opt(o1.o.s, q.o.s)
_diff_opts(o1, q)
def test_only_optiondescription():
@ -172,11 +194,7 @@ def test_diff_opt_cache():
a = dumps(o1)
q = loads(a)
_diff_opt(o1, q)
_diff_opt(o1.o, q.o)
_diff_opt(o1.o.b, q.o.b)
_diff_opt(o1.o.u, q.o.u)
_diff_opt(o1.o.s, q.o.s)
_diff_opts(o1, q)
def test_diff_opt_callback():
@ -190,11 +208,7 @@ def test_diff_opt_callback():
a = dumps(o1)
q = loads(a)
_diff_opt(o1, q)
_diff_opt(o1.o, q.o)
_diff_opt(o1.o.b, q.o.b)
_diff_opt(o1.o.b2, q.o.b2)
_diff_opt(o1.o.b3, q.o.b3)
_diff_opts(o1, q)
def test_no_state_attr():
@ -224,6 +238,7 @@ def test_state_config():
cfg._impl_test = True
a = dumps(cfg)
q = loads(a)
_diff_opts(cfg.cfgimpl_get_description(), q.cfgimpl_get_description())
_diff_conf(cfg, q)
try:
delete_session('config', '29090931')
@ -231,6 +246,35 @@ def test_state_config():
pass
def test_state_config2():
a = IPOption('a', '')
b = NetmaskOption('b', '')
dod1 = OptionDescription('dod1', '', [a, b])
b.impl_add_consistency('ip_netmask', a)
od1 = OptionDescription('od1', '', [dod1])
st1 = StrOption('st1', "", multi=True)
st2 = StrOption('st2', "", multi=True)
st3 = StrOption('st3', "", multi=True, callback=return_value, callback_params={'': ((st2, False),)})
stm = OptionDescription('st1', '', [st1, st2, st3])
stm.impl_set_group_type(groups.master)
st = OptionDescription('st', '', [stm])
od = OptionDescription('od', '', [st])
od2 = OptionDescription('od', '', [od, od1])
try:
cfg = Config(od2, persistent=True, session_id='29090939')
except ValueError:
cfg = Config(od2, session_id='29090939')
cfg._impl_test = True
a = dumps(cfg)
q = loads(a)
_diff_opts(cfg.cfgimpl_get_description(), q.cfgimpl_get_description())
_diff_conf(cfg, q)
try:
delete_session('config', '29090939')
except ConfigError:
pass
def test_state_properties():
val1 = BoolOption('val1', "")
maconfig = OptionDescription('rootconfig', '', [val1])

View File

@ -136,22 +136,32 @@ def carry_out_calculation(option, config, callback, callback_params,
"""
tcparams = {}
# if callback_params has a callback, launch several time calculate()
one_is_multi = False
master_slave = False
# multi's option should have same value for all option
len_multi = None
try:
if option._is_subdyn():
tcparams[''] = [(option.impl_getsuffix(), False)]
except AttributeError:
pass
for key, callbacks in callback_params.items():
for callbk in callbacks:
if isinstance(callbk, tuple):
if config is None:
raise ContextError()
if len(callbk) == 1:
if config is undefined:
raise ContextError() # pragma: optional cover
if len(callbk) == 1: # pragma: optional cover
tcparams.setdefault(key, []).append((config, False))
else:
# callbk is something link (opt, True|False)
opt, force_permissive = callbk
path = config.cfgimpl_get_description(
).impl_get_path_by_opt(opt)
if opt._is_subdyn():
root = '.'.join(option.impl_getpath(config).split('.')[:-1])
name = opt.impl_getname() + option.impl_getsuffix()
path = root + '.' + name
opt = opt._impl_to_dyn(name, path)
else:
path = config.cfgimpl_get_description(
).impl_get_path_by_opt(opt)
# get value
try:
value = config.getattr(path, force_permissive=True,
@ -159,7 +169,7 @@ def carry_out_calculation(option, config, callback, callback_params,
# convert to list, not modifie this multi
if value.__class__.__name__ == 'Multi':
value = list(value)
except PropertiesOptionError as err:
except PropertiesOptionError as err: # pragma: optional cover
if force_permissive:
continue
raise ConfigError(_('unable to carry out a calculation'
@ -171,7 +181,7 @@ def carry_out_calculation(option, config, callback, callback_params,
if opt.impl_is_master_slaves() and \
opt.impl_get_master_slaves().in_same_group(option):
len_multi = len(value)
one_is_multi = True
master_slave = True
is_multi = True
else:
is_multi = False
@ -183,9 +193,11 @@ def carry_out_calculation(option, config, callback, callback_params,
# if one value is a multi, launch several time calculate
# if index is set, return a value
# if no index, return a list
if one_is_multi:
if master_slave:
ret = []
if index is not undefined:
# for example if append master and get a no default slave without
# getting master
range_ = [index]
else:
range_ = range(len_multi)

View File

@ -21,7 +21,8 @@
"options handler global entry point"
import weakref
from tiramisu.error import PropertiesOptionError, ConfigError
from tiramisu.option import OptionDescription, Option, SymLinkOption
from tiramisu.option import OptionDescription, Option, SymLinkOption, \
DynSymLinkOption
from tiramisu.setting import groups, Settings, default_encoding, undefined
from tiramisu.storage import get_storages, get_storage, set_storage, \
_impl_getstate_setting
@ -47,12 +48,18 @@ class SubConfig(object):
:type subpath: `str` with the path name
"""
# main option description
if descr is not None and not isinstance(descr, OptionDescription):
error = False
try:
if descr is not None and not descr.impl_is_optiondescription(): # pragma: optional cover
error = True
except AttributeError:
error = True
if error:
raise TypeError(_('descr must be an optiondescription, not {0}'
).format(type(descr)))
self._impl_descr = descr
# sub option descriptions
if not isinstance(context, weakref.ReferenceType):
if not isinstance(context, weakref.ReferenceType): # pragma: optional cover
raise ValueError('context must be a Weakref')
self._impl_context = context
self._impl_path = subpath
@ -60,7 +67,7 @@ class SubConfig(object):
def cfgimpl_reset_cache(self, only_expired=False, only=('values',
'settings')):
"remove cache (in context)"
self._cfgimpl_get_context().cfgimpl_reset_cache(only_expired, only)
self._cfgimpl_get_context().cfgimpl_reset_cache(only_expired, only) # pragma: optional cover
def cfgimpl_get_home_by_path(self, path, force_permissive=False):
""":returns: tuple (config, name)"""
@ -93,13 +100,15 @@ class SubConfig(object):
def __iter__(self):
"""Pythonesque way of parsing group's ordered options.
iteration only on Options (not OptionDescriptions)"""
for child in self.cfgimpl_get_description().impl_getchildren():
if not isinstance(child, OptionDescription):
for child in self.cfgimpl_get_description()._impl_getchildren(
context=self._cfgimpl_get_context()):
if not child.impl_is_optiondescription():
try:
yield child.impl_getname(), getattr(self, child.impl_getname())
except GeneratorExit:
name = child.impl_getname()
yield name, getattr(self, name)
except GeneratorExit: # pragma: optional cover
raise StopIteration
except PropertiesOptionError:
except PropertiesOptionError: # pragma: optional cover
pass # option with properties
def iter_all(self, force_permissive=False):
@ -108,10 +117,10 @@ class SubConfig(object):
for child in self.cfgimpl_get_description().impl_getchildren():
try:
yield child.impl_getname(), self.getattr(child.impl_getname(),
force_permissive=force_permissive)
except GeneratorExit:
force_permissive=force_permissive)
except GeneratorExit: # pragma: optional cover
raise StopIteration
except PropertiesOptionError:
except PropertiesOptionError: # pragma: optional cover
pass # option with properties
def iter_groups(self, group_type=None, force_permissive=False):
@ -124,19 +133,20 @@ class SubConfig(object):
`setting.groups`
"""
if group_type is not None and not isinstance(group_type,
groups.GroupType):
groups.GroupType): # pragma: optional cover
raise TypeError(_("unknown group_type: {0}").format(group_type))
for child in self.cfgimpl_get_description().impl_getchildren():
if isinstance(child, OptionDescription):
for child in self.cfgimpl_get_description()._impl_getchildren(
context=self._cfgimpl_get_context()):
if child.impl_is_optiondescription():
try:
if group_type is None or (group_type is not None and
child.impl_get_group_type()
== group_type):
yield child.impl_getname(), self.getattr(child.impl_getname(),
force_permissive=force_permissive)
except GeneratorExit:
name = child.impl_getname()
yield name, self.getattr(name, force_permissive=force_permissive)
except GeneratorExit: # pragma: optional cover
raise StopIteration
except PropertiesOptionError:
except PropertiesOptionError: # pragma: optional cover
pass
# ______________________________________________________________________
@ -148,7 +158,7 @@ class SubConfig(object):
for name, value in self:
try:
lines.append("{0} = {1}".format(name, value))
except UnicodeEncodeError:
except UnicodeEncodeError: # pragma: optional cover
lines.append("{0} = {1}".format(name,
value.encode(default_encoding)))
return '\n'.join(lines)
@ -162,12 +172,12 @@ class SubConfig(object):
old `SubConfig`, `Values`, `Multi` or `Settings`)
"""
context = self._impl_context()
if context is None:
if context is None: # pragma: optional cover
raise ConfigError(_('the context does not exist anymore'))
return context
def cfgimpl_get_description(self):
if self._impl_descr is None:
if self._impl_descr is None: # pragma: optional cover
raise ConfigError(_('no option description found for this config'
' (may be GroupConfig)'))
else:
@ -183,43 +193,50 @@ class SubConfig(object):
# attribute methods
def __setattr__(self, name, value):
"attribute notation mechanism for the setting of the value of an option"
if name.startswith('_impl_'):
object.__setattr__(self, name, value)
return
self._setattr(name, value)
def _setattr(self, name, value, force_permissive=False):
if '.' in name:
if name.startswith('_impl_'):
object.__setattr__(self, name, value)
return
if '.' in name: # pragma: optional cover
homeconfig, name = self.cfgimpl_get_home_by_path(name)
return homeconfig.__setattr__(name, value)
child = getattr(self.cfgimpl_get_description(), name)
return homeconfig._setattr(name, value, force_permissive)
context = self._cfgimpl_get_context()
child = self.cfgimpl_get_description().__getattr__(name,
context=context)
if isinstance(child, OptionDescription):
raise TypeError(_("can't assign to an OptionDescription"))
elif not isinstance(child, SymLinkOption):
if self._impl_path is None:
path = name
else:
path = self._impl_path + '.' + name
self.cfgimpl_get_values().setitem(child, value, path,
force_permissive=force_permissive)
else:
context = self._cfgimpl_get_context()
raise TypeError(_("can't assign to an OptionDescription")) # pragma: optional cover
elif isinstance(child, SymLinkOption) and \
not isinstance(child, DynSymLinkOption): # pragma: no dynoptiondescription cover
path = context.cfgimpl_get_description().impl_get_path_by_opt(
child._opt)
context._setattr(path, value, force_permissive=force_permissive)
else:
subpath = self._get_subpath(name)
self.cfgimpl_get_values().setitem(child, value, subpath,
force_permissive=force_permissive)
def __delattr__(self, name):
child = getattr(self.cfgimpl_get_description(), name)
context = self._cfgimpl_get_context()
child = self.cfgimpl_get_description().__getattr__(name, context)
self.cfgimpl_get_values().__delitem__(child)
def __getattr__(self, name):
return self.getattr(name)
def _getattr(self, name, force_permissive=False, validate=True):
def _getattr(self, name, force_permissive=False, validate=True): # pragma: optional cover
"""use getattr instead of _getattr
"""
return self.getattr(name, force_permissive, validate)
def _get_subpath(self, name):
if self._impl_path is None:
subpath = name
else:
subpath = self._impl_path + '.' + name
return subpath
def getattr(self, name, force_permissive=False, validate=True):
"""
attribute notation mechanism for accessing the value of an option
@ -234,21 +251,20 @@ class SubConfig(object):
name, force_permissive=force_permissive)
return homeconfig.getattr(name, force_permissive=force_permissive,
validate=validate)
opt_or_descr = self.cfgimpl_get_description().__getattr__(name)
if self._impl_path is None:
subpath = name
else:
subpath = self._impl_path + '.' + name
# symlink options
#FIXME a gerer plutot dans l'option ca ...
#FIXME je n'en sais rien en fait ... :/
if isinstance(opt_or_descr, SymLinkOption):
context = self._cfgimpl_get_context()
context = self._cfgimpl_get_context()
opt_or_descr = self.cfgimpl_get_description().__getattr__(name, context=context)
subpath = self._get_subpath(name)
if isinstance(opt_or_descr, DynSymLinkOption):
return self.cfgimpl_get_values()._get_cached_item(
opt_or_descr, path=subpath,
validate=validate,
force_permissive=force_permissive)
elif isinstance(opt_or_descr, SymLinkOption): # pragma: no dynoptiondescription cover
path = context.cfgimpl_get_description().impl_get_path_by_opt(
opt_or_descr._opt)
return context.getattr(path, validate=validate,
force_permissive=force_permissive)
elif isinstance(opt_or_descr, OptionDescription):
elif opt_or_descr.impl_is_optiondescription():
self.cfgimpl_get_settings().validate_properties(
opt_or_descr, True, False, path=subpath,
force_permissive=force_permissive)
@ -272,7 +288,7 @@ class SubConfig(object):
return self._cfgimpl_get_context()._find(bytype, byname, byvalue,
first=False,
type_=type_,
_subpath=self.cfgimpl_get_path(),
_subpath=self.cfgimpl_get_path(False),
check_properties=check_properties,
force_permissive=force_permissive)
@ -289,7 +305,7 @@ class SubConfig(object):
"""
return self._cfgimpl_get_context()._find(
bytype, byname, byvalue, first=True, type_=type_,
_subpath=self.cfgimpl_get_path(), display_error=display_error,
_subpath=self.cfgimpl_get_path(False), display_error=display_error,
check_properties=check_properties,
force_permissive=force_permissive)
@ -311,11 +327,11 @@ class SubConfig(object):
return byvalue in value
else:
return value == byvalue
except PropertiesOptionError: # a property is a restriction
# upon the access of the value
# a property is a restriction upon the access of the value
except PropertiesOptionError: # pragma: optional cover
return False
if type_ not in ('option', 'path', 'value'):
if type_ not in ('option', 'path', 'value'): # pragma: optional cover
raise ValueError(_('unknown type_ type {0}'
'for _find').format(type_))
find_results = []
@ -324,7 +340,7 @@ class SubConfig(object):
# and so on
only_first = first is True and byvalue is None and check_properties is None
options = self.cfgimpl_get_description().impl_get_options_paths(
bytype, byname, _subpath, only_first)
bytype, byname, _subpath, only_first, self._cfgimpl_get_context())
for path, option in options:
if not _filter_by_value():
continue
@ -333,7 +349,7 @@ class SubConfig(object):
try:
value = self.getattr(path,
force_permissive=force_permissive)
except PropertiesOptionError:
except PropertiesOptionError: # pragma: optional cover
# a property restricts the access of the value
continue
if type_ == 'value':
@ -349,7 +365,7 @@ class SubConfig(object):
return self._find_return_results(find_results, display_error)
def _find_return_results(self, find_results, display_error):
if find_results == []:
if find_results == []: # pragma: optional cover
if display_error:
raise AttributeError(_("no option found in config"
" with these criteria"))
@ -400,21 +416,18 @@ class SubConfig(object):
pathsvalues = []
if _currpath is None:
_currpath = []
if withoption is None and withvalue is not undefined:
if withoption is None and withvalue is not undefined: # pragma: optional cover
raise ValueError(_("make_dict can't filtering with value without "
"option"))
if withoption is not None:
mypath = self.cfgimpl_get_path()
for path in self._cfgimpl_get_context()._find(bytype=None,
byname=withoption,
byvalue=withvalue,
first=False,
type_='path',
_subpath=mypath,
force_permissive=force_permissive):
context = self._cfgimpl_get_context()
for path in context._find(bytype=None, byname=withoption,
byvalue=withvalue, first=False,
type_='path', _subpath=self.cfgimpl_get_path(False),
force_permissive=force_permissive):
path = '.'.join(path.split('.')[:-1])
opt = self._cfgimpl_get_context().cfgimpl_get_description(
).impl_get_opt_by_path(path)
opt = context.unwrap_from_path(path, force_permissive=True)
mypath = self.cfgimpl_get_path()
if mypath is not None:
if mypath == path:
withoption = None
@ -422,7 +435,7 @@ class SubConfig(object):
break
else:
tmypath = mypath + '.'
if not path.startswith(tmypath):
if not path.startswith(tmypath): # pragma: optional cover
raise AttributeError(_('unexpected path {0}, '
'should start with {1}'
'').format(path, mypath))
@ -443,7 +456,7 @@ class SubConfig(object):
def _make_sub_dict(self, opt, path, pathsvalues, _currpath, flatten,
force_permissive=False):
try:
if isinstance(opt, OptionDescription):
if opt.impl_is_optiondescription():
pathsvalues += self.getattr(path,
force_permissive=force_permissive).make_dict(
flatten,
@ -457,13 +470,15 @@ class SubConfig(object):
else:
name = '.'.join(_currpath + [opt.impl_getname()])
pathsvalues.append((name, value))
except PropertiesOptionError:
except PropertiesOptionError: # pragma: optional cover
pass
def cfgimpl_get_path(self):
def cfgimpl_get_path(self, dyn=True):
descr = self.cfgimpl_get_description()
context_descr = self._cfgimpl_get_context().cfgimpl_get_description()
return context_descr.impl_get_path_by_opt(descr)
if not dyn and descr.impl_is_dynoptiondescription():
context_descr = self._cfgimpl_get_context().cfgimpl_get_description()
return context_descr.impl_get_path_by_opt(descr._opt)
return self._impl_path
class _CommonConfig(SubConfig):
@ -488,7 +503,7 @@ class _CommonConfig(SubConfig):
"""convenience method to retrieve an option's owner
from the config itself
"""
if not isinstance(opt, Option) and not isinstance(opt, SymLinkOption):
if not isinstance(opt, Option) and not isinstance(opt, SymLinkOption): # pragma: optional cover
raise TypeError(_('opt in getowner must be an option not {0}'
'').format(type(opt)))
return self.cfgimpl_get_values().getowner(opt,
@ -501,13 +516,14 @@ class _CommonConfig(SubConfig):
:returns: Option()
"""
context = self._cfgimpl_get_context()
if '.' in path:
homeconfig, path = self.cfgimpl_get_home_by_path(
path, force_permissive=force_permissive)
return getattr(homeconfig.cfgimpl_get_description(), path)
return getattr(self.cfgimpl_get_description(), path)
return homeconfig.cfgimpl_get_description().__getattr__(path, context=context)
return self.cfgimpl_get_description().__getattr__(path, context=context)
def cfgimpl_get_path(self):
def cfgimpl_get_path(self, dyn=True):
return None
def cfgimpl_get_meta(self):
@ -533,7 +549,7 @@ class _CommonConfig(SubConfig):
# ----- state
def __getstate__(self):
if self._impl_meta is not None:
raise ConfigError(_('cannot serialize Config with MetaConfig'))
raise ConfigError(_('cannot serialize Config with MetaConfig')) # pragma: optional cover
slots = set()
for subclass in self.__class__.__mro__:
if subclass is not object:
@ -543,12 +559,12 @@ class _CommonConfig(SubConfig):
for slot in slots:
try:
state[slot] = getattr(self, slot)
except AttributeError:
except AttributeError: # pragma: optional cover
pass
storage = self._impl_values._p_._storage
if not storage.serializable:
raise ConfigError(_('this storage is not serialisable, could be a '
'none persistent storage'))
'none persistent storage')) # pragma: optional cover
state['_storage'] = {'session_id': storage.session_id,
'persistent': storage.persistent}
state['_impl_setting'] = _impl_getstate_setting()
@ -719,6 +735,6 @@ class MetaConfig(GroupConfig):
super(MetaConfig, self).__init__(children, session_id, persistent, descr)
def mandatory_warnings(config):
def mandatory_warnings(config): # pragma: optional cover
#only for retro-compatibility
return config.cfgimpl_get_values().mandatory_warnings()

View File

@ -65,7 +65,7 @@ class ConstError(TypeError):
#Warning
class ValueWarning(UserWarning):
class ValueWarning(UserWarning): # pragma: optional cover
"""Option could warn user and not raise ValueError.
Example:

View File

@ -43,9 +43,9 @@ languages += DEFAULT_LANG
mo_location = LOCALE_DIR
if sys.version_info[0] >= 3:
if sys.version_info[0] >= 3: # pragma: optional cover
gettext.install(True, localedir=None)
else:
else: # pragma: optional cover
gettext.install(True, localedir=None, unicode=1)
gettext.find(APP_NAME, mo_location)
gettext.textdomain(APP_NAME)

View File

@ -1,6 +1,7 @@
from .masterslave import MasterSlaves
from .optiondescription import OptionDescription
from .baseoption import Option, SymLinkOption, submulti
from .optiondescription import OptionDescription, DynOptionDescription, \
SynDynOptionDescription
from .baseoption import Option, SymLinkOption, DynSymLinkOption, submulti
from .option import (ChoiceOption, BoolOption, IntOption, FloatOption,
StrOption, UnicodeOption, IPOption, PortOption,
NetworkOption, NetmaskOption, BroadcastOption,
@ -8,9 +9,10 @@ from .option import (ChoiceOption, BoolOption, IntOption, FloatOption,
FilenameOption)
__all__ = ('MasterSlaves', 'OptionDescription', 'Option', 'SymLinkOption',
'ChoiceOption', 'BoolOption', 'IntOption', 'FloatOption',
'StrOption', 'UnicodeOption', 'IPOption', 'PortOption',
'NetworkOption', 'NetmaskOption', 'BroadcastOption',
'DomainnameOption', 'EmailOption', 'URLOption', 'UsernameOption',
'FilenameOption', 'submulti')
__all__ = ('MasterSlaves', 'OptionDescription', 'DynOptionDescription',
'SynDynOptionDescription', 'Option', 'SymLinkOption',
'DynSymLinkOption', 'ChoiceOption', 'BoolOption',
'IntOption', 'FloatOption', 'StrOption', 'UnicodeOption',
'IPOption', 'PortOption', 'NetworkOption', 'NetmaskOption',
'BroadcastOption', 'DomainnameOption', 'EmailOption', 'URLOption',
'UsernameOption', 'FilenameOption', 'submulti')

View File

@ -40,7 +40,8 @@ class SubMulti(object):
submulti = SubMulti()
name_regexp = re.compile(r'^\d+')
allowed_character = '[a-z\d\-_]'
name_regexp = re.compile(r'^[a-z]{0}*$'.format(allowed_character))
forbidden_names = ('iter_all', 'iter_group', 'find', 'find_first',
'make_dict', 'unwrap_from_path', 'read_only',
'read_write', 'getowner', 'set_contexts')
@ -48,51 +49,51 @@ forbidden_names = ('iter_all', 'iter_group', 'find', 'find_first',
def valid_name(name):
"an option's name is a str and does not start with 'impl' or 'cfgimpl'"
if not isinstance(name, str):
if not isinstance(name, str): # pragma: optional cover
return False
if re.match(name_regexp, name) is None and not name.startswith('_') \
if re.match(name_regexp, name) is not None and not name.startswith('_') \
and name not in forbidden_names \
and not name.startswith('impl_') \
and not name.startswith('cfgimpl_'):
return True
else:
else: # pragma: optional cover
return False
def validate_callback(callback, callback_params, type_):
if type(callback) != FunctionType:
if type(callback) != FunctionType: # pragma: optional cover
raise ValueError(_('{0} must be a function').format(type_))
if callback_params is not None:
if not isinstance(callback_params, dict):
if not isinstance(callback_params, dict): # pragma: optional cover
raise ValueError(_('{0}_params must be a dict').format(type_))
for key, callbacks in callback_params.items():
if key != '' and len(callbacks) != 1:
if key != '' and len(callbacks) != 1: # pragma: optional cover
raise ValueError(_("{0}_params with key {1} mustn't have "
"length different to 1").format(type_,
key))
if not isinstance(callbacks, tuple):
if not isinstance(callbacks, tuple): # pragma: optional cover
raise ValueError(_('{0}_params must be tuple for key "{1}"'
).format(type_, key))
for callbk in callbacks:
if isinstance(callbk, tuple):
if len(callbk) == 1:
if callbk != (None,):
if callbk != (None,): # pragma: optional cover
raise ValueError(_('{0}_params with length of '
'tuple as 1 must only have '
'None as first value'))
elif len(callbk) != 2:
elif len(callbk) != 2: # pragma: optional cover
raise ValueError(_('{0}_params must only have 1 or 2 '
'as length'))
else:
option, force_permissive = callbk
if type_ == 'validator' and not force_permissive:
if type_ == 'validator' and not force_permissive: # pragma: optional cover
raise ValueError(_('validator not support tuple'))
if not isinstance(option, Option) and not \
isinstance(option, SymLinkOption):
isinstance(option, SymLinkOption): # pragma: optional cover
raise ValueError(_('{0}_params must have an option'
' not a {0} for first argument'
).format(type_, type(option)))
if force_permissive not in [True, False]:
if force_permissive not in [True, False]: # pragma: optional cover
raise ValueError(_('{0}_params must have a boolean'
' not a {0} for second argument'
).format(type_, type(
@ -104,11 +105,23 @@ def validate_callback(callback, callback_params, type_):
class Base(StorageBase):
__slots__ = tuple()
def impl_set_callback(self, callback, callback_params=None):
if callback is None and callback_params is not None: # pragma: optional cover
raise ValueError(_("params defined for a callback function but "
"no callback defined"
" yet for option {0}").format(
self.impl_getname()))
self._validate_callback(callback, callback_params)
if callback is not None:
validate_callback(callback, callback_params, 'callback')
self._callback = callback
self._callback_params = callback_params
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):
if not valid_name(name):
if not valid_name(name): # pragma: optional cover
raise ValueError(_("invalid name: {0} for option").format(name))
self._name = name
self._readonly = False
@ -120,13 +133,13 @@ class Base(StorageBase):
else:
self._calc_properties = frozenset()
self._requires = []
if not multi and default_multi is not None:
if not multi and default_multi is not None: # pragma: optional cover
raise ValueError(_("a default_multi is set whereas multi is False"
" in option: {0}").format(name))
if default_multi is not None:
try:
self._validate(default_multi)
except ValueError as err:
except ValueError as err: # pragma: optional cover
raise ValueError(_("invalid default_multi value {0} "
"for option {1}: {2}").format(
str(default_multi), name, err))
@ -135,16 +148,9 @@ class Base(StorageBase):
if default is None:
default = []
self._default_multi = default_multi
if callback is not None and ((not multi and (default is not None or
default_multi is not None))
or (multi and (default != [] or
default_multi is not None))
):
raise ValueError(_("default value not allowed if option: {0} "
"is calculated").format(name))
if properties is None:
properties = tuple()
if not isinstance(properties, tuple):
if not isinstance(properties, tuple): # pragma: optional cover
raise TypeError(_('invalid properties type {0} for {1},'
' must be a tuple').format(
type(properties),
@ -154,16 +160,7 @@ class Base(StorageBase):
self._validator = validator
if validator_params is not None:
self._validator_params = validator_params
if callback is None and callback_params is not None:
raise ValueError(_("params defined for a callback function but "
"no callback defined"
" yet for option {0}").format(name))
if callback is not None:
validate_callback(callback, callback_params, 'callback')
self._callback = callback
if callback_params is not None:
self._callback_params = callback_params
if self._calc_properties != frozenset([]) and properties is not tuple():
if self._calc_properties != frozenset([]) and properties is not tuple(): # pragma: optional cover
set_forbidden_properties = self._calc_properties & set(properties)
if set_forbidden_properties != frozenset():
raise ValueError('conflict: properties already set in '
@ -173,12 +170,23 @@ class Base(StorageBase):
self._default = []
else:
self._default = default
if callback is not False:
self.impl_set_callback(callback, callback_params)
self._properties = properties
self._warnings_only = warnings_only
ret = super(Base, self).__init__()
self.impl_validate(self._default)
return ret
def impl_is_optiondescription(self):
return self.__class__.__name__ in ['OptionDescription',
'DynOptionDescription',
'SynDynOptionDescription']
def impl_is_dynoptiondescription(self):
return self.__class__.__name__ in ['DynOptionDescription',
'SynDynOptionDescription']
class BaseOption(Base):
"""This abstract base class stands for attribute access
@ -204,9 +212,9 @@ class BaseOption(Base):
"""
if key in self._informations:
return self._informations[key]
elif default is not undefined:
elif default is not undefined: # pragma: optional cover
return default
else:
else: # pragma: optional cover
raise ValueError(_("information's item not found: {0}").format(
key))
@ -246,6 +254,52 @@ class BaseOption(Base):
else:
self._state_requires = new_value
def _impl_convert_callback(self, descr, load=False):
if self.__class__.__name__ == 'OptionDescription' or \
isinstance(self, SymLinkOption):
return
if not load and self._callback is None:
self._state_callback = None
self._state_callback_params = None
elif load and self._state_callback is None:
self._callback = None
self._callback_params = None
del(self._state_callback)
del(self._state_callback_params)
else:
if load:
callback = self._state_callback
callback_params = self._state_callback_params
else:
callback = self._callback
callback_params = self._callback_params
self._state_callback_params = None
if callback_params is not None:
cllbck_prms = {}
for key, values in callback_params.items():
vls = []
for value in values:
if isinstance(value, tuple):
if load:
value = (descr.impl_get_opt_by_path(value[0]),
value[1])
else:
value = (descr.impl_get_path_by_opt(value[0]),
value[1])
vls.append(value)
cllbck_prms[key] = tuple(vls)
else:
cllbck_prms = None
if load:
del(self._state_callback)
del(self._state_callback_params)
self._callback = callback
self._callback_params = cllbck_prms
else:
self._state_callback = callback
self._state_callback_params = cllbck_prms
# serialize
def _impl_getstate(self, descr):
"""the under the hood stuff that need to be done
@ -270,7 +324,7 @@ class BaseOption(Base):
"""
try:
self._stated
except AttributeError:
except AttributeError: # pragma: optional cover
raise SystemError(_('cannot serialize Option, '
'only in OptionDescription'))
slots = set()
@ -311,7 +365,7 @@ class BaseOption(Base):
self._readonly = self._state_readonly
del(self._state_readonly)
del(self._stated)
except AttributeError:
except AttributeError: # pragma: optional cover
pass
def __setstate__(self, state):
@ -350,7 +404,7 @@ class BaseOption(Base):
pass
elif name != '_readonly':
is_readonly = self.impl_is_readonly()
if is_readonly:
if is_readonly: # pragma: optional cover
raise AttributeError(_("'{0}' ({1}) object attribute '{2}' is"
" read-only").format(
self.__class__.__name__,
@ -369,6 +423,12 @@ class BaseOption(Base):
def impl_getname(self):
return self._name
def impl_getpath(self, context):
return context.cfgimpl_get_description().impl_get_path_by_opt(self)
def impl_get_callback(self):
return self._callback, self._callback_params
class OnlyOption(BaseOption):
__slots__ = tuple()
@ -440,25 +500,31 @@ class Option(OnlyOption):
:param warnings_only: specific raise error for warning
:type warnings_only: `boolean`
"""
if context is not None:
if context is not undefined:
descr = context.cfgimpl_get_description()
all_cons_vals = []
for opt in all_cons_opts:
#get value
if option == opt:
if (isinstance(opt, DynSymLinkOption) and option._dyn == opt._dyn) or \
option == opt:
opt_value = value
else:
#if context, calculate value, otherwise get default value
if context is not None:
opt_value = context.getattr(
descr.impl_get_path_by_opt(opt), validate=False,
force_permissive=True)
if context is not undefined:
if isinstance(opt, DynSymLinkOption):
path = opt.impl_getpath(context)
else:
path = descr.impl_get_path_by_opt(opt)
opt_value = context.getattr(path, validate=False,
force_permissive=True)
else:
opt_value = opt.impl_getdefault()
#append value
if not self.impl_is_multi() or option == opt:
if not self.impl_is_multi() or (isinstance(opt, DynSymLinkOption)
and option._dyn == opt._dyn) or \
option == opt:
all_cons_vals.append(opt_value)
elif self.impl_is_submulti():
try:
@ -476,8 +542,9 @@ class Option(OnlyOption):
return
getattr(self, func)(all_cons_opts, all_cons_vals, warnings_only)
def impl_validate(self, value, context=None, validate=True,
force_index=None, force_submulti_index=None):
def impl_validate(self, value, context=undefined, validate=True,
force_index=None, force_submulti_index=None,
current_opt=undefined):
"""
:param value: the option's value
:param context: Config's context
@ -493,6 +560,8 @@ class Option(OnlyOption):
"""
if not validate:
return
if current_opt is undefined:
current_opt = self
def val_validator(val):
if self._validator is not None:
@ -520,7 +589,7 @@ class Option(OnlyOption):
# option validation
try:
self._validate(_value, context)
except ValueError as err:
except ValueError as err: # pragma: optional cover
log.debug('do_validation: value: {0}, index: {1}, '
'submulti_index: {2}'.format(_value, _index,
submulti_index),
@ -533,9 +602,9 @@ class Option(OnlyOption):
# valid with self._validator
val_validator(_value)
# if not context launch consistency validation
if context is not None:
descr._valid_consistency(self, _value, context, _index,
submulti_index)
if context is not undefined:
descr._valid_consistency(current_opt, _value, context,
_index, submulti_index)
self._second_level_validation(_value, self._warnings_only)
except ValueError as error:
log.debug(_('do_validation for {0}: error in value').format(
@ -550,9 +619,9 @@ class Option(OnlyOption):
if error is None and warning is None:
try:
# if context launch consistency validation
if context is not None:
descr._valid_consistency(self, _value, context, _index,
submulti_index)
if context is not undefined:
descr._valid_consistency(current_opt, _value, context,
_index, submulti_index)
except ValueError as error:
log.debug(_('do_validation for {0}: error in consistency').format(
self.impl_getname()), exc_info=True)
@ -572,14 +641,14 @@ class Option(OnlyOption):
self._name, error))
# generic calculation
if context is not None:
if context is not undefined:
descr = context.cfgimpl_get_description()
if not self.impl_is_multi():
do_validation(value, None, None)
elif force_index is not None:
if self.impl_is_submulti() and force_submulti_index is None:
if not isinstance(value, list):
if not isinstance(value, list): # pragma: optional cover
raise ValueError(_("invalid value {0} for option {1} which"
" must be a list").format(
value, self.impl_getname()))
@ -588,13 +657,13 @@ class Option(OnlyOption):
else:
do_validation(value, force_index, force_submulti_index)
else:
if not isinstance(value, list):
if not isinstance(value, list): # pragma: optional cover
raise ValueError(_("invalid value {0} for option {1} which "
"must be a list").format(value,
self.impl_getname()))
for idx, val in enumerate(value):
if self.impl_is_submulti() and force_submulti_index is None:
if not isinstance(val, list):
if not isinstance(val, list): # pragma: optional cover
raise ValueError(_("invalid value {0} for option {1} "
"which must be a list of list"
"").format(value,
@ -651,9 +720,6 @@ class Option(OnlyOption):
else:
return True
def impl_get_callback(self):
return self._callback, self._callback_params
#def impl_getkey(self, value):
# return value
@ -673,18 +739,33 @@ class Option(OnlyOption):
:type other_opts: `list` of `tiramisu.option.Option`
:param params: extra params (only warnings_only are allowed)
"""
if self.impl_is_readonly():
if self.impl_is_readonly(): # pragma: optional cover
raise AttributeError(_("'{0}' ({1}) cannont add consistency, option is"
" read-only").format(
self.__class__.__name__,
self._name))
warnings_only = params.get('warnings_only', False)
if self._is_subdyn():
dynod = self._subdyn
else:
dynod = None
for opt in other_opts:
if not isinstance(opt, Option):
if not isinstance(opt, Option): # pragma: optional cover
raise ConfigError(_('consistency must be set with an option'))
if self is opt:
if opt._is_subdyn():
if dynod is None:
raise ConfigError(_('almost one option in consistency is '
'in a dynoptiondescription but not all'))
if dynod != opt._subdyn:
raise ConfigError(_('option in consistency must be in same'
' dynoptiondescription'))
dynod = opt._subdyn
elif dynod is not None:
raise ConfigError(_('almost one option in consistency is in a '
'dynoptiondescription but not all'))
if self is opt: # pragma: optional cover
raise ConfigError(_('cannot add consistency with itself'))
if self.impl_is_multi() != opt.impl_is_multi():
if self.impl_is_multi() != opt.impl_is_multi(): # pragma: optional cover
raise ConfigError(_('every options in consistency must be '
'multi or none'))
func = '_cons_{0}'.format(func)
@ -694,7 +775,7 @@ class Option(OnlyOption):
if self.impl_is_multi():
for idx, val in enumerate(value):
if not self.impl_is_submulti():
self._launch_consistency(func, self, val, None, idx,
self._launch_consistency(func, self, val, undefined, idx,
None, all_cons_opts,
warnings_only)
else:
@ -704,7 +785,7 @@ class Option(OnlyOption):
all_cons_opts,
warnings_only)
else:
self._launch_consistency(func, self, value, None, None,
self._launch_consistency(func, self, value, undefined, None,
None, all_cons_opts, warnings_only)
self._add_consistency(func, all_cons_opts, params)
self.impl_validate(self.impl_getdefault())
@ -720,49 +801,6 @@ class Option(OnlyOption):
raise ValueError(msg.format(opts[idx_inf].impl_getname(),
opts[idx_inf + idx_sup + 1].impl_getname()))
def _impl_convert_callbacks(self, descr, load=False):
if not load and self._callback is None:
self._state_callback = None
self._state_callback_params = None
elif load and self._state_callback is None:
self._callback = None
self._callback_params = None
del(self._state_callback)
del(self._state_callback_params)
else:
if load:
callback = self._state_callback
callback_params = self._state_callback_params
else:
callback = self._callback
callback_params = self._callback_params
self._state_callback_params = None
if callback_params is not None:
cllbck_prms = {}
for key, values in callback_params.items():
vls = []
for value in values:
if isinstance(value, tuple):
if load:
value = (descr.impl_get_opt_by_path(value[0]),
value[1])
else:
value = (descr.impl_get_path_by_opt(value[0]),
value[1])
vls.append(value)
cllbck_prms[key] = tuple(vls)
else:
cllbck_prms = None
if load:
del(self._state_callback)
del(self._state_callback_params)
self._callback = callback
self._callback_params = cllbck_prms
else:
self._state_callback = callback
self._state_callback_params = cllbck_prms
# serialize/unserialize
def _impl_convert_consistencies(self, descr, load=False):
"""during serialization process, many things have to be done.
@ -801,6 +839,24 @@ class Option(OnlyOption):
def _second_level_validation(self, value, warnings_only):
pass
def _impl_to_dyn(self, name, path):
return DynSymLinkOption(name, self, dyn=path)
def _validate_callback(self, callback, callback_params):
try:
default_multi = self._default_multi
except AttributeError:
default_multi = None
if callback is not None and ((not self._multi and
(self._default is not None or
default_multi is not None))
or (self._multi and
(self._default != [] or
default_multi is not None))
): # pragma: optional cover
raise ValueError(_("default value not allowed if option: {0} "
"is calculated").format(self.impl_getname()))
def validate_requires_arg(requires, name):
"""check malformed requirements
@ -819,60 +875,60 @@ def validate_requires_arg(requires, name):
# start parsing all requires given by user (has dict)
# transforme it to a tuple
for require in requires:
if not type(require) == dict:
if not type(require) == dict: # pragma: optional cover
raise ValueError(_("malformed requirements type for option:"
" {0}, must be a dict").format(name))
valid_keys = ('option', 'expected', 'action', 'inverse', 'transitive',
'same_action')
unknown_keys = frozenset(require.keys()) - frozenset(valid_keys)
if unknown_keys != frozenset():
raise ValueError('malformed requirements for option: {0}'
if unknown_keys != frozenset(): # pragma: optional cover
raise ValueError(_('malformed requirements for option: {0}'
' unknown keys {1}, must only '
'{2}'.format(name,
unknown_keys,
valid_keys))
'{2}').format(name,
unknown_keys,
valid_keys))
# prepare all attributes
try:
option = require['option']
expected = require['expected']
action = require['action']
except KeyError:
except KeyError: # pragma: optional cover
raise ValueError(_("malformed requirements for option: {0}"
" require must have option, expected and"
" action keys").format(name))
if action == 'force_store_value':
if action == 'force_store_value': # pragma: optional cover
raise ValueError(_("malformed requirements for option: {0}"
" action cannot be force_store_value"
).format(name))
inverse = require.get('inverse', False)
if inverse not in [True, False]:
if inverse not in [True, False]: # pragma: optional cover
raise ValueError(_('malformed requirements for option: {0}'
' inverse must be boolean'))
transitive = require.get('transitive', True)
if transitive not in [True, False]:
if transitive not in [True, False]: # pragma: optional cover
raise ValueError(_('malformed requirements for option: {0}'
' transitive must be boolean'))
same_action = require.get('same_action', True)
if same_action not in [True, False]:
if same_action not in [True, False]: # pragma: optional cover
raise ValueError(_('malformed requirements for option: {0}'
' same_action must be boolean'))
if not isinstance(option, Option):
if not isinstance(option, Option): # pragma: optional cover
raise ValueError(_('malformed requirements '
'must be an option in option {0}').format(name))
if option.impl_is_multi():
if option.impl_is_multi(): # pragma: optional cover
raise ValueError(_('malformed requirements option {0} '
'must not be a multi for {1}').format(
option.impl_getname(), name))
if expected is not None:
try:
option._validate(expected)
except ValueError as err:
except ValueError as err: # pragma: optional cover
raise ValueError(_('malformed requirements second argument '
'must be valid for option {0}'
': {1}').format(name, err))
if action in config_action:
if inverse != config_action[action]:
if inverse != config_action[action]: # pragma: optional cover
raise ValueError(_("inconsistency in action types"
" for option: {0}"
" action: {1}").format(name, action))
@ -897,23 +953,20 @@ def validate_requires_arg(requires, name):
class SymLinkOption(OnlyOption):
#FIXME : et avec sqlalchemy ca marche vraiment ?
__slots__ = ('_opt', '_state_opt')
#not return _opt consistencies
#_consistencies = None
def __init__(self, name, opt):
self._name = name
if not isinstance(opt, Option):
if not isinstance(opt, Option): # pragma: optional cover
raise ValueError(_('malformed symlinkoption '
'must be an option '
'for symlink {0}').format(name))
self._opt = opt
self._readonly = True
return super(Base, self).__init__()
super(Base, self).__init__()
def __getattr__(self, name):
if name in ('_opt', '_opt_type', '_readonly', 'impl_getname'):
def __getattr__(self, name, context=undefined):
if name in ('_opt', '_opt_type', '_readonly', 'impl_getpath'):
return object.__getattr__(self, name)
else:
return getattr(self._opt, name)
@ -929,3 +982,29 @@ class SymLinkOption(OnlyOption):
def impl_get_information(self, key, default=undefined):
return self._opt.impl_get_information(key, default)
class DynSymLinkOption(SymLinkOption):
__slots__ = ('_dyn',)
def __init__(self, name, opt, dyn):
self._dyn = dyn
super(DynSymLinkOption, self).__init__(name, opt)
def impl_getsuffix(self):
return self._dyn.split('.')[-1][len(self._opt.impl_getname()):]
def impl_getpath(self, context):
path = self._opt.impl_getpath(context)
base_path = '.'.join(path.split('.')[:-2])
if self.impl_is_master_slaves() and base_path is not '':
base_path = base_path + self.impl_getsuffix()
if base_path == '':
return self._dyn
else:
return base_path + '.' + self._dyn
def impl_validate(self, value, context=undefined, validate=True,
force_index=None, force_submulti_index=None):
return self._opt.impl_validate(value, context, validate, force_index,
force_submulti_index, current_opt=self)

View File

@ -22,63 +22,92 @@
from tiramisu.i18n import _
from tiramisu.setting import log, undefined
from tiramisu.error import SlaveError, ConfigError
from .baseoption import SymLinkOption, Option
from .baseoption import DynSymLinkOption, SymLinkOption, Option
class MasterSlaves(object):
__slots__ = ('master', 'slaves')
def __init__(self, name, childs):
def __init__(self, name, childs, validate=True):
#if master (same name has group) is set
#for collect all slaves
self.master = None
slaves = []
for child in childs:
if isinstance(child, SymLinkOption):
if isinstance(child, SymLinkOption): # pragma: optional cover
raise ValueError(_("master group {0} shall not have "
"a symlinkoption").format(name))
if not isinstance(child, Option):
if not isinstance(child, Option): # pragma: optional cover
raise ValueError(_("master group {0} shall not have "
"a subgroup").format(name))
if not child.impl_is_multi():
if not child.impl_is_multi(): # pragma: optional cover
raise ValueError(_("not allowed option {0} "
"in group {1}"
": this option is not a multi"
"").format(child._name, name))
if child._name == name:
"").format(child.impl_getname(), name))
if child.impl_getname() == name:
self.master = child
else:
slaves.append(child)
if self.master is None:
if self.master is None: # pragma: optional cover
raise ValueError(_('master group with wrong'
' master name for {0}'
).format(name))
callback, callback_params = self.master.impl_get_callback()
if callback is not None and callback_params is not None:
for key, callbacks in callback_params.items():
for callbk in callbacks:
if isinstance(callbk, tuple):
if callbk[0] in slaves:
raise ValueError(_("callback of master's option shall "
"not refered a slave's ones"))
if validate:
callback, callback_params = self.master.impl_get_callback()
if callback is not None and callback_params is not None: # pragma: optional cover
for key, callbacks in callback_params.items():
for callbk in callbacks:
if isinstance(callbk, tuple):
if callbk[0] in slaves:
raise ValueError(_("callback of master's option shall "
"not refered a slave's ones"))
#everything is ok, store references
self.slaves = tuple(slaves)
for child in childs:
child._master_slaves = self
def is_master(self, opt):
return opt == self.master
return opt == self.master or (isinstance(opt, DynSymLinkOption) and
opt._opt == self.master)
def getmaster(self, opt):
if isinstance(opt, DynSymLinkOption):
suffix = opt.impl_getsuffix()
name = self.master.impl_getname() + suffix
base_path = opt._dyn.split('.')[0] + '.'
path = base_path + name
master = self.master._impl_to_dyn(name, path)
else: # pragma: no dynoptiondescription cover
master = self.master
return master
def getslaves(self, opt):
if isinstance(opt, DynSymLinkOption):
for slave in self.slaves:
suffix = opt.impl_getsuffix()
name = slave.impl_getname() + suffix
base_path = opt._dyn.split('.')[0] + '.'
path = base_path + name
yield slave._impl_to_dyn(name, path)
else: # pragma: no dynoptiondescription cover
for slave in self.slaves:
yield slave
def in_same_group(self, opt):
return opt == self.master or opt in self.slaves
if isinstance(opt, DynSymLinkOption):
return opt._opt == self.master or opt._opt in self.slaves
else: # pragma: no dynoptiondescription cover
return opt == self.master or opt in self.slaves
def reset(self, values):
for slave in self.slaves:
def reset(self, opt, values):
#FIXME pas de opt ???
for slave in self.getslaves(opt):
values.reset(slave)
def pop(self, values, index):
def pop(self, opt, values, index):
#FIXME pas test de meta ...
for slave in self.slaves:
for slave in self.getslaves(opt):
if not values.is_default_owner(slave, validate_properties=False,
validate_meta=False):
values._get_cached_item(slave, validate=False,
@ -89,7 +118,7 @@ class MasterSlaves(object):
def getitem(self, values, opt, path, validate, force_permissive,
force_properties, validate_properties, slave_path=undefined,
slave_value=undefined):
if opt == self.master:
if self.is_master(opt):
return self._getmaster(values, opt, path, validate,
force_permissive, force_properties,
validate_properties, slave_path,
@ -108,9 +137,9 @@ class MasterSlaves(object):
validate_properties)
if validate is True:
masterlen = len(value)
for slave in self.slaves:
for slave in self.getslaves(opt):
try:
slave_path = values._get_opt_path(slave)
slave_path = slave.impl_getpath(values._getcontext())
if c_slave_path == slave_path:
slave_value = c_slave_value
else:
@ -121,8 +150,8 @@ class MasterSlaves(object):
None, False,
None) # not undefined
slavelen = len(slave_value)
self.validate_slave_length(masterlen, slavelen, slave._name)
except ConfigError:
self.validate_slave_length(masterlen, slavelen, slave.impl_getname(), opt)
except ConfigError: # pragma: optional cover
pass
return value
@ -136,10 +165,10 @@ class MasterSlaves(object):
return self.get_slave_value(values, opt, value, validate, validate_properties)
def setitem(self, values, opt, value, path):
if opt == self.master:
if self.is_master(opt):
masterlen = len(value)
for slave in self.slaves:
slave_path = values._get_opt_path(slave)
for slave in self.getslaves(opt):
slave_path = slave.impl_getpath(values._getcontext())
slave_value = values._get_validated_value(slave,
slave_path,
False,
@ -147,24 +176,28 @@ class MasterSlaves(object):
None, False,
None) # not undefined
slavelen = len(slave_value)
self.validate_slave_length(masterlen, slavelen, slave._name)
self.validate_slave_length(masterlen, slavelen, slave.impl_getname(), opt)
else:
self.validate_slave_length(self.get_length(values), len(value),
opt._name, setitem=True)
self.validate_slave_length(self.get_length(values, opt,
slave_path=path), len(value),
opt.impl_getname(), opt, setitem=True)
def get_length(self, values, validate=True, slave_path=undefined,
def get_length(self, values, opt, validate=True, slave_path=undefined,
slave_value=undefined):
masterp = values._get_opt_path(self.master)
return len(self.getitem(values, self.master, masterp, validate, False,
"""get master len with slave option"""
masterp = self.getmaster(opt).impl_getpath(values._getcontext())
if slave_value is undefined:
slave_path = undefined
return len(self.getitem(values, self.getmaster(opt), masterp, validate, False,
None, True, slave_path, slave_value))
def validate_slave_length(self, masterlen, valuelen, name, setitem=False):
if valuelen > masterlen or (valuelen < masterlen and setitem):
def validate_slave_length(self, masterlen, valuelen, name, opt, setitem=False):
if valuelen > masterlen or (valuelen < masterlen and setitem): # pragma: optional cover
log.debug('validate_slave_length: masterlen: {0}, valuelen: {1}, '
'setitem: {2}'.format(masterlen, valuelen, setitem))
raise SlaveError(_("invalid len for the slave: {0}"
" which has {1} as master").format(
name, self.master._name))
name, self.getmaster(opt).impl_getname()))
def get_slave_value(self, values, opt, value, validate=True,
validate_properties=True):
@ -190,11 +223,11 @@ class MasterSlaves(object):
list is greater than master: raise SlaveError
"""
#if slave, had values until master's one
path = values._get_opt_path(opt)
masterlen = self.get_length(values, validate, path, value)
path = opt.impl_getpath(values._getcontext())
masterlen = self.get_length(values, opt, validate, path, value)
valuelen = len(value)
if validate:
self.validate_slave_length(masterlen, valuelen, opt._name)
self.validate_slave_length(masterlen, valuelen, opt.impl_getname(), opt)
if valuelen < masterlen:
for num in range(0, masterlen - valuelen):
index = valuelen + num

View File

@ -23,7 +23,7 @@ import re
import sys
from IPy import IP
from types import FunctionType
from tiramisu.setting import log
from tiramisu.setting import log, undefined
from tiramisu.error import ConfigError, ContextError
from tiramisu.i18n import _
@ -48,7 +48,7 @@ class ChoiceOption(Option):
"""
if isinstance(values, FunctionType):
validate_callback(values, values_params, 'values')
elif not isinstance(values, tuple):
elif not isinstance(values, tuple): # pragma: optional cover
raise TypeError(_('values must be a tuple or a function for {0}'
).format(name))
self._extra = {'_choice_values': values,
@ -74,20 +74,20 @@ class ChoiceOption(Option):
values = carry_out_calculation(self, config=context,
callback=values,
callback_params=values_params)
if not isinstance(values, list):
if not isinstance(values, list): # pragma: optional cover
raise ConfigError(_('calculated values for {0} is not a list'
'').format(self.impl_getname()))
return values
def _validate(self, value, context=None):
def _validate(self, value, context=undefined):
try:
values = self.impl_get_values(context)
if not value in values:
if not value in values: # pragma: optional cover
raise ValueError(_('value {0} is not permitted, '
'only {1} is allowed'
'').format(value,
values))
except ContextError:
except ContextError: # pragma: optional cover
log.debug('ChoiceOption validation, disabled because no context')
@ -95,39 +95,39 @@ class BoolOption(Option):
"represents a choice between ``True`` and ``False``"
__slots__ = tuple()
def _validate(self, value, context=None):
def _validate(self, value, context=undefined):
if not isinstance(value, bool):
raise ValueError(_('invalid boolean'))
raise ValueError(_('invalid boolean')) # pragma: optional cover
class IntOption(Option):
"represents a choice of an integer"
__slots__ = tuple()
def _validate(self, value, context=None):
def _validate(self, value, context=undefined):
if not isinstance(value, int):
raise ValueError(_('invalid integer'))
raise ValueError(_('invalid integer')) # pragma: optional cover
class FloatOption(Option):
"represents a choice of a floating point number"
__slots__ = tuple()
def _validate(self, value, context=None):
def _validate(self, value, context=undefined):
if not isinstance(value, float):
raise ValueError(_('invalid float'))
raise ValueError(_('invalid float')) # pragma: optional cover
class StrOption(Option):
"represents the choice of a string"
__slots__ = tuple()
def _validate(self, value, context=None):
def _validate(self, value, context=undefined):
if not isinstance(value, str):
raise ValueError(_('invalid string'))
raise ValueError(_('invalid string')) # pragma: optional cover
if sys.version_info[0] >= 3:
if sys.version_info[0] >= 3: # pragma: optional cover
#UnicodeOption is same as StrOption in python 3+
class UnicodeOption(StrOption):
__slots__ = tuple()
@ -138,9 +138,9 @@ else:
__slots__ = tuple()
_empty = u''
def _validate(self, value, context=None):
def _validate(self, value, context=undefined):
if not isinstance(value, unicode):
raise ValueError(_('invalid unicode'))
raise ValueError(_('invalid unicode')) # pragma: optional cover
class IPOption(Option):
@ -165,31 +165,31 @@ class IPOption(Option):
properties=properties,
warnings_only=warnings_only)
def _validate(self, value, context=None):
def _validate(self, value, context=undefined):
# sometimes an ip term starts with a zero
# but this does not fit in some case, for example bind does not like it
try:
for val in value.split('.'):
if val.startswith("0") and len(val) > 1:
raise ValueError(_('invalid IP'))
except AttributeError:
raise ValueError(_('invalid IP')) # pragma: optional cover
except AttributeError: # pragma: optional cover
#if integer for example
raise ValueError(_('invalid IP'))
# 'standard' validation
try:
IP('{0}/32'.format(value))
except ValueError:
except ValueError: # pragma: optional cover
raise ValueError(_('invalid IP'))
def _second_level_validation(self, value, warnings_only):
ip = IP('{0}/32'.format(value))
if not self._extra['_allow_reserved'] and ip.iptype() == 'RESERVED':
if not self._extra['_allow_reserved'] and ip.iptype() == 'RESERVED': # pragma: optional cover
if warnings_only:
msg = _("IP is in reserved class")
else:
msg = _("invalid IP, mustn't be in reserved class")
raise ValueError(msg)
if self._extra['_private_only'] and not ip.iptype() == 'PRIVATE':
if self._extra['_private_only'] and not ip.iptype() == 'PRIVATE': # pragma: optional cover
if warnings_only:
msg = _("IP is not in private class")
else:
@ -198,11 +198,11 @@ class IPOption(Option):
def _cons_in_network(self, opts, vals, warnings_only):
if len(vals) != 3:
raise ConfigError(_('invalid len for vals'))
raise ConfigError(_('invalid len for vals')) # pragma: optional cover
if None in vals:
return
ip, network, netmask = vals
if IP(ip) not in IP('{0}/{1}'.format(network, netmask)):
if IP(ip) not in IP('{0}/{1}'.format(network, netmask)): # pragma: optional cover
if warnings_only:
msg = _('IP {0} ({1}) not in network {2} ({3}) with netmask {4}'
' ({5})')
@ -247,12 +247,12 @@ class PortOption(Option):
elif not allowed:
is_finally = True
elif allowed and is_finally:
raise ValueError(_('inconsistency in allowed range'))
raise ValueError(_('inconsistency in allowed range')) # pragma: optional cover
if allowed:
extra['_max_value'] = ports_max[index]
if extra['_max_value'] is None:
raise ValueError(_('max value is empty'))
raise ValueError(_('max value is empty')) # pragma: optional cover
self._extra = extra
super(PortOption, self).__init__(name, doc, default=default,
@ -266,8 +266,8 @@ class PortOption(Option):
properties=properties,
warnings_only=warnings_only)
def _validate(self, value, context=None):
if self._extra['_allow_range'] and ":" in str(value):
def _validate(self, value, context=undefined):
if self._extra['_allow_range'] and ":" in str(value): # pragma: optional cover
value = str(value).split(':')
if len(value) != 2:
raise ValueError(_('invalid port, range must have two values '
@ -281,9 +281,9 @@ class PortOption(Option):
for val in value:
try:
val = int(val)
except ValueError:
except ValueError: # pragma: optional cover
raise ValueError(_('invalid port'))
if not self._extra['_min_value'] <= val <= self._extra['_max_value']:
if not self._extra['_min_value'] <= val <= self._extra['_max_value']: # pragma: optional cover
raise ValueError(_('invalid port, must be an between {0} '
'and {1}').format(self._extra['_min_value'],
self._extra['_max_value']))
@ -293,15 +293,15 @@ class NetworkOption(Option):
"represents the choice of a network"
__slots__ = tuple()
def _validate(self, value, context=None):
def _validate(self, value, context=undefined):
try:
IP(value)
except ValueError:
except ValueError: # pragma: optional cover
raise ValueError(_('invalid network address'))
def _second_level_validation(self, value, warnings_only):
ip = IP(value)
if ip.iptype() == 'RESERVED':
if ip.iptype() == 'RESERVED': # pragma: optional cover
if warnings_only:
msg = _("network address is in reserved class")
else:
@ -313,10 +313,10 @@ class NetmaskOption(Option):
"represents the choice of a netmask"
__slots__ = tuple()
def _validate(self, value, context=None):
def _validate(self, value, context=undefined):
try:
IP('0.0.0.0/{0}'.format(value))
except ValueError:
except ValueError: # pragma: optional cover
raise ValueError(_('invalid netmask address'))
def _cons_network_netmask(self, opts, vals, warnings_only):
@ -334,7 +334,7 @@ class NetmaskOption(Option):
def __cons_netmask(self, opts, val_netmask, val_ipnetwork, make_net,
warnings_only):
if len(opts) != 2:
raise ConfigError(_('invalid len for opts'))
raise ConfigError(_('invalid len for opts')) # pragma: optional cover
msg = None
try:
ip = IP('{0}/{1}'.format(val_ipnetwork, val_netmask),
@ -347,14 +347,14 @@ class NetmaskOption(Option):
except ValueError:
pass
else:
if make_net:
if make_net: # pragma: optional cover
msg = _("invalid IP {0} ({1}) with netmask {2},"
" this IP is a network")
except ValueError:
except ValueError: # pragma: optional cover
if not make_net:
msg = _('invalid network {0} ({1}) with netmask {2}')
if msg is not None:
if msg is not None: # pragma: optional cover
raise ValueError(msg.format(val_ipnetwork, opts[1].impl_getname(),
val_netmask))
@ -362,15 +362,15 @@ class NetmaskOption(Option):
class BroadcastOption(Option):
__slots__ = tuple()
def _validate(self, value, context=None):
def _validate(self, value, context=undefined):
try:
IP('{0}/32'.format(value))
except ValueError:
except ValueError: # pragma: optional cover
raise ValueError(_('invalid broadcast address'))
def _cons_broadcast(self, opts, vals, warnings_only):
if len(vals) != 3:
raise ConfigError(_('invalid len for vals'))
raise ConfigError(_('invalid len for vals')) # pragma: optional cover
if None in vals:
return
broadcast, network, netmask = vals
@ -378,7 +378,7 @@ class BroadcastOption(Option):
raise ValueError(_('invalid broadcast {0} ({1}) with network {2} '
'({3}) and netmask {4} ({5})').format(
broadcast, opts[0].impl_getname(), network,
opts[1].impl_getname(), netmask, opts[2].impl_getname()))
opts[1].impl_getname(), netmask, opts[2].impl_getname())) # pragma: optional cover
class DomainnameOption(Option):
@ -396,12 +396,12 @@ class DomainnameOption(Option):
properties=None, allow_ip=False, type_='domainname',
warnings_only=False, allow_without_dot=False):
if type_ not in ['netbios', 'hostname', 'domainname']:
raise ValueError(_('unknown type_ {0} for hostname').format(type_))
raise ValueError(_('unknown type_ {0} for hostname').format(type_)) # pragma: optional cover
self._extra = {'_dom_type': type_}
if allow_ip not in [True, False]:
raise ValueError(_('allow_ip must be a boolean'))
raise ValueError(_('allow_ip must be a boolean')) # pragma: optional cover
if allow_without_dot not in [True, False]:
raise ValueError(_('allow_without_dot must be a boolean'))
raise ValueError(_('allow_without_dot must be a boolean')) # pragma: optional cover
self._extra['_allow_ip'] = allow_ip
self._extra['_allow_without_dot'] = allow_without_dot
end = ''
@ -410,17 +410,17 @@ class DomainnameOption(Option):
if self._extra['_dom_type'] != 'netbios':
allow_number = '\d'
else:
allow_number = ''
allow_number = '' # pragma: optional cover
if self._extra['_dom_type'] == 'netbios':
length = 14
length = 14 # pragma: optional cover
elif self._extra['_dom_type'] == 'hostname':
length = 62
length = 62 # pragma: optional cover
elif self._extra['_dom_type'] == 'domainname':
length = 62
if allow_without_dot is False:
extrachar_mandatory = '\.'
else:
extrachar = '\.'
extrachar = '\.' # pragma: optional cover
end = '+[a-z]*'
self._extra['_domain_re'] = re.compile(r'^(?:[a-z{0}][a-z\d\-{1}]{{,{2}}}{3}){4}$'
''.format(allow_number, extrachar, length,
@ -436,37 +436,37 @@ class DomainnameOption(Option):
properties=properties,
warnings_only=warnings_only)
def _validate(self, value, context=None):
if self._extra['_allow_ip'] is True:
def _validate(self, value, context=undefined):
if self._extra['_allow_ip'] is True: # pragma: optional cover
try:
IP('{0}/32'.format(value))
return
except ValueError:
pass
if self._extra['_dom_type'] == 'domainname' and not self._extra['_allow_without_dot'] and \
'.' not in value:
'.' not in value: # pragma: optional cover
raise ValueError(_("invalid domainname, must have dot"))
if len(value) > 255:
raise ValueError(_("invalid domainname's length (max 255)"))
raise ValueError(_("invalid domainname's length (max 255)")) # pragma: optional cover
if len(value) < 2:
raise ValueError(_("invalid domainname's length (min 2)"))
raise ValueError(_("invalid domainname's length (min 2)")) # pragma: optional cover
if not self._extra['_domain_re'].search(value):
raise ValueError(_('invalid domainname'))
raise ValueError(_('invalid domainname')) # pragma: optional cover
class EmailOption(DomainnameOption):
__slots__ = tuple()
username_re = re.compile(r"^[\w!#$%&'*+\-/=?^`{|}~.]+$")
def _validate(self, value, context=None):
def _validate(self, value, context=undefined):
splitted = value.split('@', 1)
try:
username, domain = splitted
except ValueError:
except ValueError: # pragma: optional cover
raise ValueError(_('invalid email address, must contains one @'
))
if not self.username_re.search(username):
raise ValueError(_('invalid username in email address'))
raise ValueError(_('invalid username in email address')) # pragma: optional cover
super(EmailOption, self)._validate(domain)
@ -475,9 +475,9 @@ class URLOption(DomainnameOption):
proto_re = re.compile(r'(http|https)://')
path_re = re.compile(r"^[a-z0-9\-\._~:/\?#\[\]@!%\$&\'\(\)\*\+,;=]+$")
def _validate(self, value, context=None):
def _validate(self, value, context=undefined):
match = self.proto_re.search(value)
if not match:
if not match: # pragma: optional cover
raise ValueError(_('invalid url, must start with http:// or '
'https://'))
value = value[len(match.group(0)):]
@ -493,17 +493,17 @@ class URLOption(DomainnameOption):
try:
domain, port = splitted
except ValueError:
except ValueError: # pragma: optional cover
domain = splitted[0]
port = 0
if not 0 <= int(port) <= 65535:
raise ValueError(_('invalid url, port must be an between 0 and '
'65536'))
'65536')) # pragma: optional cover
# validate domainname
super(URLOption, self)._validate(domain)
# validate file
if files is not None and files != '' and not self.path_re.search(files):
raise ValueError(_('invalid url, must ends with filename'))
raise ValueError(_('invalid url, must ends with filename')) # pragma: optional cover
class UsernameOption(Option):
@ -511,17 +511,17 @@ class UsernameOption(Option):
#regexp build with 'man 8 adduser' informations
username_re = re.compile(r"^[a-z_][a-z0-9_-]{0,30}[$a-z0-9_-]{0,1}$")
def _validate(self, value, context=None):
def _validate(self, value, context=undefined):
match = self.username_re.search(value)
if not match:
raise ValueError(_('invalid username'))
raise ValueError(_('invalid username')) # pragma: optional cover
class FilenameOption(Option):
__slots__ = tuple()
path_re = re.compile(r"^[a-zA-Z0-9\-\._~/+]+$")
def _validate(self, value, context=None):
def _validate(self, value, context=undefined):
match = self.path_re.search(value)
if not match:
raise ValueError(_('invalid filename'))
raise ValueError(_('invalid filename')) # pragma: optional cover

View File

@ -19,16 +19,21 @@
# the whole pypy projet is under MIT licence
# ____________________________________________________________
from copy import copy
import re
from tiramisu.i18n import _
from tiramisu.setting import groups # , log
from .baseoption import BaseOption
from tiramisu.setting import groups, undefined # , log
from .baseoption import BaseOption, DynSymLinkOption, SymLinkOption, \
allowed_character
from . import MasterSlaves
from tiramisu.error import ConfigError, ConflictError, ValueWarning
from tiramisu.storage import get_storages_option
from tiramisu.autolib import carry_out_calculation
StorageOptionDescription = get_storages_option('optiondescription')
name_regexp = re.compile(r'^{0}*$'.format(allowed_character))
class OptionDescription(BaseOption, StorageOptionDescription):
@ -42,16 +47,31 @@ class OptionDescription(BaseOption, StorageOptionDescription):
:param children: a list of options (including optiondescriptions)
"""
super(OptionDescription, self).__init__(name, doc=doc, requires=requires, properties=properties)
child_names = [child.impl_getname() for child in children]
super(OptionDescription, self).__init__(name, doc=doc,
requires=requires,
properties=properties,
callback=False)
child_names = []
dynopt_names = []
for child in children:
name = child.impl_getname()
child_names.append(name)
if isinstance(child, DynOptionDescription):
dynopt_names.append(name)
#better performance like this
valid_child = copy(child_names)
valid_child.sort()
old = None
for child in valid_child:
if child == old:
if child == old: # pragma: optional cover
raise ConflictError(_('duplicate option name: '
'{0}').format(child))
if dynopt_names:
for dynopt in dynopt_names:
if child != dynopt and child.startswith(dynopt):
raise ConflictError(_('option must not start as '
'dynoptiondescription'))
old = child
self._add_children(child_names, children)
self._cache_paths = None
@ -74,19 +94,7 @@ class OptionDescription(BaseOption, StorageOptionDescription):
"""returns a list of all paths in self, recursively
_currpath should not be provided (helps with recursion)
"""
if _currpath is None:
_currpath = []
paths = []
for option in self.impl_getchildren():
attr = option.impl_getname()
if isinstance(option, OptionDescription):
if include_groups:
paths.append('.'.join(_currpath + [attr]))
paths += option.impl_getpaths(include_groups=include_groups,
_currpath=_currpath + [attr])
else:
paths.append('.'.join(_currpath + [attr]))
return paths
return _impl_getpaths(self, include_groups, _currpath)
def impl_build_cache_consistency(self, _consistencies=None, cache_option=None):
#FIXME cache_option !
@ -96,7 +104,7 @@ class OptionDescription(BaseOption, StorageOptionDescription):
cache_option = []
else:
init = False
for option in self.impl_getchildren():
for option in self._impl_getchildren(dyn=False):
cache_option.append(option._get_id())
if not isinstance(option, OptionDescription):
for func, all_cons_opts, params in option._get_consistencies():
@ -111,7 +119,7 @@ class OptionDescription(BaseOption, StorageOptionDescription):
self._cache_consistencies = {}
for opt, cons in _consistencies.items():
#FIXME dans le cache ...
if opt._get_id() not in cache_option:
if opt._get_id() not in cache_option: # pragma: optional cover
raise ConfigError(_('consistency with option {0} '
'which is not in Config').format(
opt.impl_getname()))
@ -125,13 +133,13 @@ class OptionDescription(BaseOption, StorageOptionDescription):
cache_option = []
else:
init = False
for option in self.impl_getchildren():
for option in self._impl_getchildren(dyn=False):
#FIXME specifique id for sqlalchemy?
#FIXME avec sqlalchemy ca marche le multi parent ? (dans des configs différentes)
#if option.id is None:
# raise SystemError(_("an option's id should not be None "
# "for {0}").format(option.impl_getname()))
if option._get_id() in cache_option:
if option._get_id() in cache_option: # pragma: optional cover
raise ConflictError(_('duplicate option: {0}').format(option))
cache_option.append(option._get_id())
option._readonly = True
@ -147,7 +155,7 @@ class OptionDescription(BaseOption, StorageOptionDescription):
:param group_type: an instance of `GroupType` or `MasterGroupType`
that lives in `setting.groups`
"""
if self._group_type != groups.default:
if self._group_type != groups.default: # pragma: optional cover
raise TypeError(_('cannot change group_type if already set '
'(old {0}, new {1})').format(self._group_type,
group_type))
@ -155,7 +163,7 @@ class OptionDescription(BaseOption, StorageOptionDescription):
self._group_type = group_type
if isinstance(group_type, groups.MasterGroupType):
MasterSlaves(self.impl_getname(), self.impl_getchildren())
else:
else: # pragma: optional cover
raise ValueError(_('group_type: {0}'
' not allowed').format(group_type))
@ -166,18 +174,29 @@ class OptionDescription(BaseOption, StorageOptionDescription):
if self._cache_consistencies is None:
return True
#consistencies is something like [('_cons_not_equal', (opt1, opt2))]
consistencies = self._cache_consistencies.get(option)
if isinstance(option, DynSymLinkOption):
consistencies = self._cache_consistencies.get(option._opt)
else:
consistencies = self._cache_consistencies.get(option)
if consistencies is not None:
for func, all_cons_opts, params in consistencies:
warnings_only = params.get('warnings_only', False)
#all_cons_opts[0] is the option where func is set
if isinstance(option, DynSymLinkOption):
subpath = '.'.join(option._dyn.split('.')[:-1])
namelen = len(option._opt.impl_getname())
suffix = option.impl_getname()[namelen:]
opts = []
for opt in all_cons_opts:
name = opt.impl_getname() + suffix
path = subpath + '.' + name
opts.append(opt._impl_to_dyn(name, path))
else:
opts = all_cons_opts
try:
all_cons_opts[0]._launch_consistency(func, option,
value,
context, index,
submulti_idx,
all_cons_opts,
warnings_only)
opts[0]._launch_consistency(func, option, value, context,
index, submulti_idx, opts,
warnings_only)
except ValueError as err:
if warnings_only:
raise ValueWarning(err.message, option)
@ -189,12 +208,13 @@ class OptionDescription(BaseOption, StorageOptionDescription):
:param descr: parent :class:`tiramisu.option.OptionDescription`
"""
if descr is None:
self.impl_build_cache_consistency()
#FIXME faut le desactiver ?
#self.impl_build_cache_consistency()
self.impl_build_cache_option()
descr = self
super(OptionDescription, self)._impl_getstate(descr)
self._state_group_type = str(self._group_type)
for option in self.impl_getchildren():
for option in self._impl_getchildren():
option._impl_getstate(descr)
def __getstate__(self):
@ -224,9 +244,12 @@ class OptionDescription(BaseOption, StorageOptionDescription):
self.impl_build_cache_option()
descr = self
self._group_type = getattr(groups, self._state_group_type)
if isinstance(self._group_type, groups.MasterGroupType):
MasterSlaves(self.impl_getname(), self.impl_getchildren(),
validate=False)
del(self._state_group_type)
super(OptionDescription, self)._impl_setstate(descr)
for option in self.impl_getchildren():
for option in self._impl_getchildren(dyn=False):
option._impl_setstate(descr)
def __setstate__(self, state):
@ -235,3 +258,129 @@ class OptionDescription(BaseOption, StorageOptionDescription):
self._stated
except AttributeError:
self._impl_setstate()
def _impl_get_suffixes(self, context):
callback, callback_params = self.impl_get_callback()
if callback_params is None:
callback_params = {}
values = carry_out_calculation(self, config=context,
callback=callback,
callback_params=callback_params)
if len(values) > len(set(values)):
raise ConfigError(_('DynOptionDescription callback return not uniq value'))
for val in values:
if not isinstance(val, str) or re.match(name_regexp, val) is None:
raise ValueError(_("invalid suffix: {0} for option").format(val))
return values
def _impl_search_dynchild(self, name=undefined, context=undefined):
ret = []
for child in self._impl_st_getchildren():
cname = child.impl_getname()
if isinstance(child, DynOptionDescription) and \
(name is undefined or name.startswith(cname)):
path = cname
for value in child._impl_get_suffixes(context):
if name is undefined:
ret.append(SynDynOptionDescription(child, cname + value, path + value, value))
elif name == cname + value:
return SynDynOptionDescription(child, name, path + value, value)
return ret
def _impl_get_dynchild(self, child, suffix):
name = child.impl_getname() + suffix
path = self._name + suffix + '.' + name
if isinstance(child, OptionDescription):
return SynDynOptionDescription(child, name, path, suffix)
else:
return child._impl_to_dyn(name, path)
def _impl_getchildren(self, dyn=True, context=undefined):
for child in self._impl_st_getchildren():
cname = child._name
if dyn and child.impl_is_dynoptiondescription():
path = cname
for value in child._impl_get_suffixes(context):
yield SynDynOptionDescription(child,
cname + value,
path + value, value)
else:
yield child
def impl_getchildren(self):
return list(self._impl_getchildren())
class DynOptionDescription(OptionDescription):
def __init__(self, name, doc, children, requires=None, properties=None,
callback=None, callback_params=None):
for child in children:
if isinstance(child, OptionDescription):
if child.impl_get_group_type() != groups.master:
raise ConfigError(_('cannot set optiondescription in an '
'dynoptiondescription'))
for chld in child._impl_getchildren():
chld._subdyn = self
if isinstance(child, SymLinkOption):
raise ConfigError(_('cannot set symlinkoption in an '
'dynoptiondescription'))
child._subdyn = self
super(DynOptionDescription, self).__init__(name, doc, children,
requires, properties)
self.impl_set_callback(callback, callback_params)
def _validate_callback(self, callback, callback_params):
if callback is None:
raise ConfigError(_('callback is mandatory for dynoptiondescription'))
class SynDynOptionDescription(object):
__slots__ = ('_opt', '_name', '_path', '_suffix')
def __init__(self, opt, name, path, suffix):
self._opt = opt
self._name = name
self._path = path
self._suffix = suffix
def __getattr__(self, name, context=undefined):
if name in dir(self._opt):
return getattr(self._opt, name)
return self._opt._getattr(name, self._name, self._suffix, context)
def impl_getname(self):
return self._name
def _impl_getchildren(self, dyn=True, context=undefined):
children = []
for child in self._opt._impl_getchildren():
children.append(self._opt._impl_get_dynchild(child, self._suffix))
return children
def impl_getchildren(self):
return self._impl_getchildren()
def impl_getpath(self, context):
return self._path
def impl_getpaths(self, include_groups=False, _currpath=None):
return _impl_getpaths(self, include_groups, _currpath)
def _impl_getpaths(klass, include_groups, _currpath):
"""returns a list of all paths in klass, recursively
_currpath should not be provided (helps with recursion)
"""
if _currpath is None:
_currpath = []
paths = []
for option in klass._impl_getchildren():
attr = option.impl_getname()
if option.impl_is_optiondescription():
if include_groups:
paths.append('.'.join(_currpath + [attr]))
paths += option.impl_getpaths(include_groups=include_groups,
_currpath=_currpath + [attr])
else:
paths.append('.'.join(_currpath + [attr]))
return paths

View File

@ -114,11 +114,11 @@ class _NameSpace(object):
"""
def __setattr__(self, name, value):
if name in self.__dict__:
if name in self.__dict__: # pragma: optional cover
raise ConstError(_("can't rebind {0}").format(name))
self.__dict__[name] = value
def __delattr__(self, name):
def __delattr__(self, name): # pragma: optional cover
if name in self.__dict__:
raise ConstError(_("can't unbind {0}").format(name))
raise ValueError(name)
@ -248,7 +248,7 @@ class Property(object):
:type propname: string
"""
if self._opt is not None and self._opt.impl_getrequires() is not None \
and propname in self._opt._calc_properties:
and propname in self._opt._calc_properties: # pragma: optional cover
raise ValueError(_('cannot append {0} property for option {1}: '
'this property is calculated').format(
propname, self._opt.impl_getname()))
@ -315,7 +315,7 @@ class Settings(object):
old `SubConfig`, `Values`, `Multi` or `Settings`)
"""
context = self.context()
if context is None:
if context is None: # pragma: optional cover
raise ConfigError(_('the context does not exist anymore'))
return context
@ -329,24 +329,24 @@ class Settings(object):
return str(list(self._getproperties()))
def __getitem__(self, opt):
path = self._get_path_by_opt(opt)
path = opt.impl_getpath(self._getcontext())
return self._getitem(opt, path)
def _getitem(self, opt, path):
return Property(self, self._getproperties(opt, path), opt, path)
def __setitem__(self, opt, value):
def __setitem__(self, opt, value): # pragma: optional cover
raise ValueError('you should only append/remove properties')
def reset(self, opt=None, _path=None, all_properties=False):
if all_properties and (_path or opt):
if all_properties and (_path or opt): # pragma: optional cover
raise ValueError(_('opt and all_properties must not be set '
'together in reset'))
if all_properties:
self._p_.reset_all_properties()
else:
if opt is not None and _path is None:
_path = self._get_path_by_opt(opt)
_path = opt.impl_getpath(self._getcontext())
self._p_.reset_properties(_path)
self._getcontext().cfgimpl_reset_cache()
@ -357,7 +357,7 @@ class Settings(object):
if opt is None:
props = copy(self._p_.getproperties(path, default_properties))
else:
if path is None:
if path is None: # pragma: optional cover
raise ValueError(_('if opt is not None, path should not be'
' None in _getproperties'))
ntime = None
@ -491,15 +491,15 @@ class Settings(object):
instead of passing a :class:`tiramisu.option.Option()` object.
"""
if opt is not None and path is None:
path = self._get_path_by_opt(opt)
if not isinstance(permissive, tuple):
path = opt.impl_getpath(self._getcontext())
if not isinstance(permissive, tuple): # pragma: optional cover
raise TypeError(_('permissive must be a tuple'))
self._p_.setpermissive(path, permissive)
#____________________________________________________________
def setowner(self, owner):
":param owner: sets the default value for owner at the Config level"
if not isinstance(owner, owners.Owner):
if not isinstance(owner, owners.Owner): # pragma: optional cover
raise TypeError(_("invalid generic owner {0}").format(str(owner)))
self._owner = owner
@ -586,8 +586,8 @@ class Settings(object):
for require in requires:
option, expected, action, inverse, \
transitive, same_action = require
reqpath = self._get_path_by_opt(option)
if reqpath == path or reqpath.startswith(path + '.'):
reqpath = option.impl_getpath(context)
if reqpath == path or reqpath.startswith(path + '.'): # pragma: optional cover
raise RequirementError(_("malformed requirements "
"imbrication detected for option:"
" '{0}' with requirement on: "
@ -598,7 +598,7 @@ class Settings(object):
if not transitive:
continue
properties = err.proptype
if same_action and action not in properties:
if same_action and action not in properties: # pragma: optional cover
raise RequirementError(_("option '{0}' has "
"requirement's property "
"error: "
@ -616,14 +616,6 @@ class Settings(object):
break
return calc_properties
def _get_path_by_opt(self, opt):
"""just a wrapper to get path in optiondescription's cache
:param opt: `Option`'s object
:returns: path
"""
return self._getcontext().cfgimpl_get_description().impl_get_path_by_opt(opt)
def get_modified_properties(self):
return self._p_.get_modified_properties()

View File

@ -40,7 +40,7 @@ class StorageType(object):
storage_type = None
mod = None
def set(self, name):
def set(self, name): # pragma: optional cover
if self.storage_type is not None:
if self.storage_type == name:
return
@ -63,7 +63,7 @@ storage_type = StorageType()
storage_option_type = StorageType()
def set_storage(type_, name, **kwargs):
def set_storage(type_, name, **kwargs): # pragma: optional cover
"""Change storage's configuration
:params name: is the storage name. If storage is already set, cannot
@ -95,7 +95,7 @@ def _impl_getstate_setting():
return state
def get_storage(type_, session_id, persistent, test):
def get_storage(type_, session_id, persistent, test): # pragma: optional cover
"""all used when __setstate__ a Config
"""
if type_ == 'option':
@ -123,7 +123,7 @@ def get_storages_option(type_):
return imp.OptionDescription
def list_sessions(type_):
def list_sessions(type_): # pragma: optional cover
"""List all available session (persistent or not persistent)
"""
if type_ == 'option':
@ -132,7 +132,7 @@ def list_sessions(type_):
return storage_type.get().list_sessions()
def delete_session(type_, session_id):
def delete_session(type_, session_id): # pragma: optional cover
"""Delete a selected session, be careful, you can deleted a session
use by an other instance
:params session_id: id of session to delete

View File

@ -18,7 +18,8 @@
#
# ____________________________________________________________
from tiramisu.i18n import _
from tiramisu.setting import groups
from tiramisu.setting import groups, undefined
from tiramisu.error import ConfigError
#____________________________________________________________
@ -32,9 +33,14 @@ class Base(object):
'_default', '_default_multi', '_state_callback', '_callback',
'_state_callback_params', '_callback_params', '_multitype',
'_consistencies', '_warnings_only', '_master_slaves',
'_state_consistencies', '_extra', '__weakref__')
'_state_consistencies', '_extra', '_subdyn', '__weakref__',
'_state_master_slaves')
def __init__(self):
try:
self._subdyn
except AttributeError:
self._subdyn = False
try:
self._consistencies
except AttributeError:
@ -65,6 +71,12 @@ class Base(object):
def _get_id(self):
return id(self)
def _is_subdyn(self):
try:
return self._subdyn is not False
except AttributeError:
return False
class OptionDescription(Base):
__slots__ = ('_children', '_cache_paths', '_cache_consistencies',
@ -82,20 +94,21 @@ class OptionDescription(Base):
def impl_get_opt_by_path(self, path):
try:
return self._cache_paths[0][self._cache_paths[1].index(path)]
except ValueError:
except ValueError: # pragma: optional cover
raise AttributeError(_('no option for path {0}').format(path))
def impl_get_path_by_opt(self, opt):
try:
return self._cache_paths[1][self._cache_paths[0].index(opt)]
except ValueError:
except ValueError: # pragma: optional cover
raise AttributeError(_('no option {0} found').format(opt))
def impl_get_group_type(self):
def impl_get_group_type(self): # pragma: optional cover
return getattr(groups, self._group_type)
def impl_build_cache_option(self, _currpath=None, cache_path=None, cache_option=None):
if _currpath is None and self._cache_paths is not None:
def impl_build_cache_option(self, _currpath=None, cache_path=None,
cache_option=None):
if _currpath is None and self._cache_paths is not None: # pragma: optional cover
# cache already set
return
if _currpath is None:
@ -106,11 +119,12 @@ class OptionDescription(Base):
if cache_path is None:
cache_path = []
cache_option = []
for option in self.impl_getchildren():
for option in self._impl_getchildren(dyn=False):
attr = option._name
path = str('.'.join(_currpath + [attr]))
cache_option.append(option)
cache_path.append(str('.'.join(_currpath + [attr])))
if option.__class__.__name__ == 'OptionDescription':
cache_path.append(path)
if option.impl_is_optiondescription():
_currpath.append(attr)
option.impl_build_cache_option(_currpath, cache_path,
cache_option)
@ -118,52 +132,141 @@ class OptionDescription(Base):
if save:
self._cache_paths = (tuple(cache_option), tuple(cache_path))
def impl_get_options_paths(self, bytype, byname, _subpath, only_first):
def _filter_by_name():
if byname is None or path == byname or \
path.endswith('.' + byname):
return True
return False
def _filter_by_type():
if bytype is None:
return True
if isinstance(option, bytype):
return True
return False
def impl_get_options_paths(self, bytype, byname, _subpath, only_first, context):
find_results = []
def _rebuild_dynpath(path, suffix, dynopt):
found = False
spath = path.split('.')
for length in xrange(1, len(spath)):
subpath = '.'.join(spath[0:length])
subopt = self.impl_get_opt_by_path(subpath)
if dynopt == subopt:
found = True
break
if not found:
#FIXME
raise ConfigError(_('hu?'))
subpath = subpath + suffix
for slength in xrange(length, len(spath)):
subpath = subpath + '.' + spath[slength] + suffix
return subpath
def _filter_by_name(path, option):
name = option.impl_getname()
if option._is_subdyn():
if byname.startswith(name):
found = False
for suffix in option._subdyn._impl_get_suffixes(
context):
if byname == name + suffix:
found = True
path = _rebuild_dynpath(path, suffix,
option._subdyn)
option = option._impl_to_dyn(
name + suffix, path)
break
if not found:
return False
else:
if not byname == name:
return False
find_results.append((path, option))
return True
def _filter_by_type(path, option):
if isinstance(option, bytype):
#if byname is not None, check option byname in _filter_by_name
#not here
if byname is None:
if option._is_subdyn():
name = option.impl_getname()
for suffix in option._subdyn._impl_get_suffixes(
context):
spath = _rebuild_dynpath(path, suffix,
option._subdyn)
find_results.append((spath, option._impl_to_dyn(
name + suffix, spath)))
else:
find_results.append((path, option))
return True
return False
def _filter(path, option):
if bytype is not None:
retval = _filter_by_type(path, option)
if byname is None:
return retval
if byname is not None:
return _filter_by_name(path, option)
opts, paths = self._cache_paths
for index in range(0, len(paths)):
option = opts[index]
if option.__class__.__name__ == 'OptionDescription':
if option.impl_is_optiondescription():
continue
path = paths[index]
if _subpath is not None and not path.startswith(_subpath + '.'):
continue
if not _filter_by_name():
continue
if not _filter_by_type():
continue
retval = (path, option)
if bytype == byname is None:
if option._is_subdyn():
name = option.impl_getname()
for suffix in option._subdyn._impl_get_suffixes(
context):
spath = _rebuild_dynpath(path, suffix,
option._subdyn)
find_results.append((spath, option._impl_to_dyn(
name + suffix, spath)))
else:
find_results.append((path, option))
else:
if _filter(path, option) is False:
continue
if only_first:
return retval
find_results.append(retval)
return find_results[0]
return find_results
def impl_getchildren(self):
def _impl_st_getchildren(self):
return self._children[1]
def __getattr__(self, name):
def __getattr__(self, name, context=undefined):
if name == '_name':
return object.__getattribute__(self, name)
try:
if name == '_readonly':
raise AttributeError("{0} instance has no attribute "
"'_readonly'".format(
self.__class__.__name__))
return self._children[1][self._children[0].index(name)]
except ValueError:
return self._getattr(name, context=context)
def _getattr(self, name, dyn_od=undefined, suffix=undefined,
context=undefined, dyn=True):
error = False
if suffix is not undefined:
try:
if undefined in [dyn_od, suffix, context]: # pragma: optional cover
raise ConfigError(_("dyn_od, suffix and context needed if "
"it's a dyn option"))
if name.endswith(suffix):
oname = name[:-len(suffix)]
child = self._children[1][self._children[0].index(oname)]
return self._impl_get_dynchild(child, suffix)
else:
error = True
except ValueError: # pragma: optional cover
error = True
else:
try: # pragma: optional cover
if name == '_readonly':
raise AttributeError(_("{0} instance has no attribute "
"'_readonly'").format(
self.__class__.__name__))
child = self._children[1][self._children[0].index(name)]
if dyn and child.impl_is_dynoptiondescription():
error = True
else:
return child
except ValueError:
child = self._impl_search_dynchild(name, context=context)
if child != []:
return child
error = True
if error:
raise AttributeError(_('unknown Option {0} '
'in OptionDescription {1}'
'').format(name, self._name))

View File

@ -29,11 +29,11 @@ setting = Setting()
_list_sessions = []
def list_sessions():
def list_sessions(): # pragma: optional cover
return _list_sessions
def delete_session(session_id):
def delete_session(session_id): # pragma: optional cover
raise ConfigError(_('dictionary storage cannot delete session'))
@ -44,9 +44,9 @@ class Storage(object):
serializable = True
def __init__(self, session_id, persistent, test=False):
if not test and session_id in _list_sessions:
if not test and session_id in _list_sessions: # pragma: optional cover
raise ValueError(_('session already used'))
if persistent:
if persistent: # pragma: optional cover
raise ValueError(_('a dictionary cannot be persistent'))
self.session_id = session_id
self.persistent = persistent
@ -55,5 +55,5 @@ class Storage(object):
def __del__(self):
try:
_list_sessions.remove(self.session_id)
except AttributeError:
except AttributeError: # pragma: optional cover
pass

View File

@ -88,5 +88,5 @@ class Values(Cache):
"""
if key in self._informations:
return self._informations[key]
else:
else: # pragma: optional cover
raise ValueError("not found")

View File

@ -1,6 +1,6 @@
# -*- coding: utf-8 -*-
"takes care of the option's values and multi values"
# Copyright (C) 2013 Team tiramisu (see AUTHORS for all contributors)
# Copyright (C) 2013-2014 Team tiramisu (see AUTHORS for all contributors)
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by the
@ -22,7 +22,7 @@ from tiramisu.error import ConfigError, SlaveError, PropertiesOptionError
from tiramisu.setting import owners, expires_time, undefined
from tiramisu.autolib import carry_out_calculation
from tiramisu.i18n import _
from tiramisu.option import SymLinkOption, OptionDescription
from tiramisu.option import SymLinkOption, DynSymLinkOption
class Values(object):
@ -50,7 +50,7 @@ class Values(object):
old `SubConfig`, `Values`, `Multi` or `Settings`)
"""
context = self.context()
if context is None:
if context is None: # pragma: optional cover
raise ConfigError(_('the context does not exist anymore'))
return context
@ -60,9 +60,11 @@ class Values(object):
: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'))
setting = self._getcontext().cfgimpl_get_settings()
force_default = 'frozen' in setting[opt] and \
'force_default_on_freeze' in setting[opt]
force_default = 'frozen' in setting._getitem(opt, path) and \
'force_default_on_freeze' in setting._getitem(opt, path)
if not is_default and not force_default:
value = self._p_.getvalue(path)
if index is not undefined:
@ -101,7 +103,7 @@ class Values(object):
#FIXME : problème de longueur si meta + slave
#doit passer de meta à pas meta
#en plus il faut gérer la longueur avec les meta !
#FIXME SymlinkOption
#FIXME SymLinkOption
value = meta.cfgimpl_get_values()[opt]
if isinstance(value, Multi):
if index is not undefined:
@ -136,7 +138,7 @@ class Values(object):
:param opt: the `option.Option()` object
"""
path = self._get_opt_path(opt)
path = opt.impl_getpath(self._getcontext())
return self._contains(path)
def _contains(self, path):
@ -148,7 +150,7 @@ class Values(object):
def reset(self, opt, path=None):
if path is None:
path = self._get_opt_path(opt)
path = opt.impl_getpath(self._getcontext())
if self._p_.hasvalue(path):
context = self._getcontext()
setting = context.cfgimpl_get_settings()
@ -156,7 +158,7 @@ class Values(object):
context, 'validator' in setting)
context.cfgimpl_reset_cache()
if opt.impl_is_master_slaves('master'):
opt.impl_get_master_slaves().reset(self)
opt.impl_get_master_slaves().reset(opt, self)
self._p_.resetvalue(path)
def _isempty(self, opt, value):
@ -186,7 +188,7 @@ class Values(object):
force_permissive=False, force_properties=None,
validate_properties=True):
if path is None:
path = self._get_opt_path(opt)
path = opt.impl_getpath(self._getcontext())
ntime = None
setting = self._getcontext().cfgimpl_get_settings()
if 'cache' in setting and self._p_.hascache(path):
@ -275,13 +277,13 @@ class Values(object):
force_submulti_index = None
else:
force_submulti_index = submulti_index
opt.impl_validate(value, context, 'validator' in setting,
force_index=force_index,
force_submulti_index=force_submulti_index)
#FIXME pas de test avec les metas ...
#FIXME et les symlinkoption ...
if is_default and 'force_store_value' in setting[opt]:
if is_default and 'force_store_value' in setting._getitem(opt,
path):
if isinstance(value, Multi):
item = list(value)
else:
@ -297,7 +299,7 @@ class Values(object):
raise config_error
return value
def __setitem__(self, opt, value):
def __setitem__(self, opt, value): # pragma: optional cover
raise ValueError(_('you should only set value with config'))
def setitem(self, opt, value, path, force_permissive=False,
@ -342,9 +344,10 @@ class Values(object):
was present
:returns: a `setting.owners.Owner` object
"""
if isinstance(opt, SymLinkOption):
if isinstance(opt, SymLinkOption) and \
not isinstance(opt, DynSymLinkOption):
opt = opt._opt
path = self._get_opt_path(opt)
path = opt.impl_getpath(self._getcontext())
return self._getowner(opt, path, force_permissive=force_permissive)
def _getowner(self, opt, path, validate_properties=True,
@ -365,14 +368,14 @@ class Values(object):
:param opt: the `option.Option` object
:param owner: a valid owner, that is a `setting.owners.Owner` object
"""
if not isinstance(owner, owners.Owner):
if not isinstance(owner, owners.Owner): # pragma: optional cover
raise TypeError(_("invalid generic owner {0}").format(str(owner)))
path = self._get_opt_path(opt)
path = opt.impl_getpath(self._getcontext())
self._setowner(opt, path, owner)
def _setowner(self, opt, path, owner):
if self._getowner(opt, path) == owners.default:
if self._getowner(opt, path) == owners.default: # pragma: optional cover
raise ConfigError(_('no value for {0} cannot change owner to {1}'
'').format(path, owner))
self._p_.setowner(path, owner)
@ -384,7 +387,7 @@ class Values(object):
(not the toplevel config)
:return: boolean
"""
path = self._get_opt_path(opt)
path = opt.impl_getpath(self._getcontext())
return self._is_default_owner(opt, path,
validate_properties=validate_properties,
validate_meta=validate_meta)
@ -403,16 +406,6 @@ class Values(object):
else:
self._p_.reset_all_cache()
def _get_opt_path(self, opt):
"""
retrieve the option's path in the config
:param opt: the `option.Option` object
:returns: a string with points like "gc.dummy.my_option"
"""
return self._getcontext().cfgimpl_get_description(
).impl_get_path_by_opt(opt)
# information
def set_information(self, key, value):
"""updates the information's attribute
@ -429,7 +422,7 @@ class Values(object):
"""
try:
return self._p_.get_information(key)
except ValueError:
except ValueError: # pragma: optional cover
if default is not undefined:
return default
else:
@ -445,22 +438,26 @@ class Values(object):
"""
def _mandatory_warnings(description):
#if value in cache, properties are not calculated
for opt in description.impl_getchildren():
if isinstance(opt, OptionDescription):
_mandatory_warnings(opt)
elif isinstance(opt, SymLinkOption):
_ret = []
for opt in description._impl_getchildren(
context=self._getcontext()):
if opt.impl_is_optiondescription():
_ret.extend(_mandatory_warnings(opt))
elif isinstance(opt, SymLinkOption) and \
not isinstance(opt, DynSymLinkOption):
pass
else:
path = self._get_opt_path(opt)
path = opt.impl_getpath(self._getcontext())
try:
self._get_cached_item(opt, path=path,
force_properties=frozenset(('mandatory',)))
except PropertiesOptionError as err:
if err.proptype == ['mandatory']:
yield path
_ret.append(path)
return _ret
self.reset_cache(False)
descr = self._getcontext().cfgimpl_get_description()
ret = list(_mandatory_warnings(descr))
ret = _mandatory_warnings(descr)
self.reset_cache(False)
return ret
@ -507,12 +504,12 @@ class Multi(list):
"""
if value is None:
value = []
if not opt.impl_is_submulti() and isinstance(value, Multi):
if not opt.impl_is_submulti() and isinstance(value, Multi): # pragma: optional cover
raise ValueError(_('{0} is already a Multi ').format(
opt.impl_getname()))
self.opt = opt
self.path = path
if not isinstance(context, weakref.ReferenceType):
if not isinstance(context, weakref.ReferenceType): # pragma: optional cover
raise ValueError('context must be a Weakref')
self.context = context
if not isinstance(value, list):
@ -542,7 +539,7 @@ class Multi(list):
old `SubConfig`, `Values`, `Multi` or `Settings`)
"""
context = self.context()
if context is None:
if context is None: # pragma: optional cover
raise ConfigError(_('the context does not exist anymore'))
return context
@ -574,7 +571,7 @@ class Multi(list):
only if the option is a master
"""
if not force:
if self.opt.impl_is_master_slaves('slave'):
if self.opt.impl_is_master_slaves('slave'): # pragma: optional cover
raise SlaveError(_("cannot append a value on a multi option {0}"
" which is a slave").format(self.opt.impl_getname()))
index = self.__len__()
@ -650,12 +647,12 @@ class Multi(list):
"""
context = self._getcontext()
if not force:
if self.opt.impl_is_master_slaves('slave'):
if self.opt.impl_is_master_slaves('slave'): # pragma: optional cover
raise SlaveError(_("cannot pop a value on a multi option {0}"
" which is a slave").format(self.opt.impl_getname()))
if self.opt.impl_is_master_slaves('master'):
self.opt.impl_get_master_slaves().pop(
context.cfgimpl_get_values(), index)
self.opt.impl_get_master_slaves().pop(self.opt,
context.cfgimpl_get_values(), index)
#set value without valid properties
ret = super(Multi, self).pop(index)
self._store(force)