From 7ab7b810dc7cf851ba969fd2a87b6a03372df247 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Sun, 12 Nov 2017 14:33:05 +0100 Subject: [PATCH] refactor --- test/api/test_multi.py | 248 +++++++ test/api/test_owner.py | 219 +++--- test/test_multi.py | 47 +- test/test_submulti.py | 392 +---------- tiramisu/api.py | 147 ++-- tiramisu/config.py | 411 +++++++---- tiramisu/option/baseoption.py | 15 +- tiramisu/option/option.py | 73 +- tiramisu/option/optiondescription.py | 250 ++++--- tiramisu/setting.py | 24 +- tiramisu/storage/dictionary/value.py | 14 +- tiramisu/storage/util.py | 34 + tiramisu/value.py | 985 ++++++++++++--------------- 13 files changed, 1439 insertions(+), 1420 deletions(-) create mode 100644 test/api/test_multi.py diff --git a/test/api/test_multi.py b/test/api/test_multi.py new file mode 100644 index 0000000..d45b6e5 --- /dev/null +++ b/test/api/test_multi.py @@ -0,0 +1,248 @@ +"""test consistencies about multi and submulti""" +from py.test import raises +from .autopath import do_autopath +do_autopath() +from tiramisu.setting import groups +from tiramisu import Config, StrOption, IntOption, OptionDescription, MasterSlaves, getapi, \ + submulti, undefined +from tiramisu.error import PropertiesOptionError + + +def return_val(val=None): + if val is None: + return 'val' + else: + return val + + +def return_list(value=None): + return ['val', 'val'] + + +def return_list2(value=None): + return [['val', 'val']] + + +def test_multi_unique(): + int_ = IntOption('int', '', multi=True, unique=True) + od_ = OptionDescription('od', '', [int_]) + cfg = Config(od_) + api = getapi(cfg) + assert api.option('int').value.get() == [] + value = [0] + api.option('int').value.set(value) + assert api.option('int').value.get() == value + value.append(1) + assert api.option('int').value.get() == [0] + raises(ValueError, "api.option('int').value.set([0, 0])") + raises(ValueError, "api.option('int').value.set([1, 0, 2, 3, 4, 5, 6, 0, 7])") + + +def test_multi_none(): + str_ = StrOption('str', '', multi=True) + od_ = OptionDescription('od', '', [str_]) + cfg = Config(od_) + cfg.read_only() + api = getapi(cfg) + assert api.option('str').value.get() == [] + cfg.read_write() + api.option('str').value.set([None]) + assert api.option('str').value.get() == [None] + cfg.read_only() + raises(PropertiesOptionError, "api.option('str').value.get()") + cfg.read_write() + api.option('str').value.set(['']) + assert api.option('str').value.get() == [''] + cfg.read_only() + raises(PropertiesOptionError, "api.option('str').value.get()") + + +# ______________ submulti ______________ + +def test_append_submulti(): + multi = StrOption('multi', '', multi=submulti) + multi2 = StrOption('multi2', '', default_multi=['yes'], multi=submulti) + multi3 = StrOption('multi3', '', default=[['yes']], multi=submulti) + od_ = OptionDescription('od', '', [multi, multi2, multi3]) + cfg = Config(od_) + api = getapi(cfg) + #FIXME + owner = cfg.cfgimpl_get_settings().getowner() + assert api.option('multi').value.get() == [] + assert api.option('multi').value.get() == [] + assert api.option('multi').owner.isdefault() + api.option('multi').value.set([undefined]) + assert api.option('multi').owner.get() == owner + value = api.option('multi').value.get() + assert value == [[]] + value.append(['no']) + assert api.option('multi').value.get() == [[]] + api.option('multi').value.set(value) + assert api.option('multi').value.get() == [[], ['no']] + # + assert api.option('multi2').value.get() == [] + assert api.option('multi2').owner.isdefault() + api.option('multi2').value.set([undefined]) + assert api.option('multi2').owner.get() == owner + assert api.option('multi2').value.get() == [['yes']] + api.option('multi2').value.set([['yes'], ['no']]) + assert api.option('multi2').value.get() == [['yes'], ['no']] + # + assert api.option('multi3').value.get() == [['yes']] + assert api.option('multi3').owner.isdefault() + api.option('multi3').value.set([['yes'], undefined]) + assert api.option('multi3').owner.get() == owner + assert api.option('multi3').value.get() == [['yes'], []] + api.option('multi3').value.set([['yes'], [], ['no']]) + assert api.option('multi3').value.get() == [['yes'], [], ['no']] + + +def test_append_unvalide_submulti(): + multi = StrOption('multi', '', multi=submulti) + multi2 = StrOption('multi2', '', default_multi=['yes'], multi=submulti) + multi3 = StrOption('multi3', '', default=[['yes']], multi=submulti) + od_ = OptionDescription('od', '', [multi, multi2, multi3]) + cfg = Config(od_) + api = getapi(cfg) + assert api.option('multi').value.get() == [] + assert api.option('multi').owner.isdefault() + raises(ValueError, "api.option('multi').value.set([1])") + assert api.option('multi').value.get() == [] + assert api.option('multi').owner.isdefault() + # + assert api.option('multi2').value.get() == [] + raises(ValueError, "api.option('multi2').value.set('no')") + assert api.option('multi2').owner.isdefault() + assert api.option('multi2').value.get() == [] + # + assert api.option('multi3').value.get() == [['yes']] + assert api.option('multi3').owner.isdefault() + + +def test_submulti_unique(): + int_ = IntOption('int', '', multi=submulti, unique=True) + od_ = OptionDescription('od', '', [int_]) + cfg = Config(od_) + api = getapi(cfg) + assert api.option('int').value.get() == [] + api.option('int').value.set([[0]]) + assert api.option('int').value.get() == [[0]] + raises(ValueError, "api.option('int').value.set([[0, 0]])") + api.option('int').value.set([[0], [0]]) + raises(ValueError, "api.option('int').value.set([[0], [1, 0, 2, 3, 4, 5, 6, 0, 7]])") + + +def test_callback_reset(): + multi = StrOption('multi', '', multi=submulti, callback=return_val) + od_ = OptionDescription('od', '', [multi]) + cfg = Config(od_) + cfg.read_write() + api = getapi(cfg) + #FIXME + owner = cfg.cfgimpl_get_settings().getowner() + assert api.option('multi').value.get() == [['val']] + assert api.option('multi').owner.isdefault() + api.option('multi').value.set([['val'], undefined]) + assert api.option('multi').owner.get() == owner + assert api.option('multi').value.get() == [['val'], ['val']] + api.option('multi').value.reset() + assert api.option('multi').owner.isdefault() + assert api.option('multi').value.get() == [['val']] + api.option('multi').value.set([['val1']]) + assert api.option('multi').owner.get() == owner + assert api.option('multi').value.get() == [['val1']] + + +def test_callback_submulti_list(): + multi = StrOption('multi', '', multi=submulti, callback=return_list) + od_ = OptionDescription('od', '', [multi]) + cfg = Config(od_) + cfg.read_write() + api = getapi(cfg) + owner = cfg.cfgimpl_get_settings().getowner() + assert api.option('multi').value.get() == [['val', 'val']] + assert api.option('multi').owner.isdefault() + api.option('multi').value.set([['val', 'val'], undefined]) + assert api.option('multi').owner.get() == owner + assert api.option('multi').value.get() == [['val', 'val'], ['val', 'val']] + api.option('multi').value.set([['val', 'val'], undefined, undefined]) + assert api.option('multi').value.get() == [['val', 'val'], ['val', 'val'], ['val', 'val']] + api.option('multi').value.reset() + assert api.option('multi').owner.isdefault() + + +def test_callback_submulti_list_list(): + multi = StrOption('multi', '', multi=submulti, callback=return_list2) + od = OptionDescription('od', '', [multi]) + cfg = Config(od) + cfg.read_write() + api = getapi(cfg) + owner = cfg.cfgimpl_get_settings().getowner() + assert api.option('multi').value.get() == [['val', 'val']] + assert api.option('multi').owner.isdefault() + api.option('multi').value.set([['val', 'val'], undefined]) + assert api.option('multi').owner.get() == owner + assert api.option('multi').value.get() == [['val', 'val'], []] + api.option('multi').value.reset() + assert api.option('multi').owner.isdefault() + + +#FIXME +#def test_multi_submulti_meta(): +# multi = StrOption('multi', '', multi=submulti) +# od = OptionDescription('od', '', [multi]) +# conf1 = Config(od, session_id='conf1') +# conf1.read_write() +# conf2 = Config(od, session_id='conf2') +# conf2.read_write() +# meta = MetaConfig([conf1, conf2]) +# meta.read_write() +# meta.multi = [['val']] +# assert meta.multi == [['val']] +# multi = conf1.multi[0] +# multi.append() +# assert conf1.multi == [['val', None]] +# assert meta.multi == [['val']] + + +# ____________________________________________________________ +# Master Slaves + + +def test_values_with_master_and_slaves_submulti(): + ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True) + netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=submulti) + interface1 = MasterSlaves('f_ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0]) + conf = OptionDescription('conf', '', [interface1]) + cfg = Config(conf) + api = getapi(cfg) + cfg.read_write() + owner = cfg.cfgimpl_get_settings().getowner() + #FIXME + assert interface1.impl_get_group_type() == groups.master + assert api.option('f_ip_admin_eth0.ip_admin_eth0').owner.isdefault() + #FIXME raises(IndexError, "api.option('f_ip_admin_eth0.netmask_admin_eth0', 0).value.get()") + api.option('f_ip_admin_eth0.ip_admin_eth0').value.set(['192.168.230.145']) + assert api.option('f_ip_admin_eth0.ip_admin_eth0').value.get() == ['192.168.230.145'] + assert api.option('f_ip_admin_eth0.netmask_admin_eth0', 0).value.get() == [] + #FIXME raises(IndexError, "api.option('f_ip_admin_eth0.netmask_admin_eth0', 1).value.get()") + assert api.option('f_ip_admin_eth0.ip_admin_eth0').owner.get() == owner + assert api.option('f_ip_admin_eth0.netmask_admin_eth0', 0).owner.isdefault() + api.option('f_ip_admin_eth0.ip_admin_eth0').value.set(['192.168.230.145', '192.168.230.147']) + assert api.option('f_ip_admin_eth0.netmask_admin_eth0', 0).value.get() == [] + assert api.option('f_ip_admin_eth0.netmask_admin_eth0', 1).value.get() == [] + #FIXME raises(IndexError, "api.option('f_ip_admin_eth0.netmask_admin_eth0', 2).value.get()") + #FIXME raises(IndexError, "api.option('f_ip_admin_eth0.netmask_admin_eth0', 2).value.set(['255.255.255.0'])") + api.option('f_ip_admin_eth0.netmask_admin_eth0', 0).value.set(['255.255.255.0']) + assert api.option('f_ip_admin_eth0.netmask_admin_eth0', 0).value.get() == ['255.255.255.0'] + assert api.option('f_ip_admin_eth0.netmask_admin_eth0', 1).value.get() == [] + api.option('f_ip_admin_eth0.netmask_admin_eth0', 1).value.set(['255.255.255.255']) + assert api.option('f_ip_admin_eth0.netmask_admin_eth0', 0).value.get() == ['255.255.255.0'] + assert api.option('f_ip_admin_eth0.netmask_admin_eth0', 1).value.get() == ['255.255.255.255'] + assert api.option('f_ip_admin_eth0.ip_admin_eth0').value.get() == ['192.168.230.145', '192.168.230.147'] + raises(ValueError, "api.option('f_ip_admin_eth0.ip_admin_eth0').value.set(['192.168.230.145'])") + api.option('f_ip_admin_eth0.ip_admin_eth0').value.pop(1) + assert api.option('f_ip_admin_eth0.ip_admin_eth0').value.get() == ['192.168.230.145'] + assert api.option('f_ip_admin_eth0.netmask_admin_eth0', 0).value.get() == ['255.255.255.0'] + #FIXME raises(IndexError, "api.option('f_ip_admin_eth0.netmask_admin_eth0', 1).value.get()") + diff --git a/test/api/test_owner.py b/test/api/test_owner.py index 8a5ea94..4b6cb48 100644 --- a/test/api/test_owner.py +++ b/test/api/test_owner.py @@ -138,18 +138,15 @@ def autocheck_value(api, path, **kwargs): if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False): if ismaster: raises(APIError, "api.option(path, 0).value.set(first_value[0])") - api.option(path).value.append(first_value[0]) + api.option(path).value.set([first_value[0]]) elif isslave: - #FIXME - print(api.option(path).value.append(first_value[0])) - raises(PropertiesOptionError, "api.option(path).value.append(first_value[0])") api.option(path, 0).value.set(first_value[0]) raise Exception('pouet') else: api.option(path).value.set(first_value) else: if ismaster: - raises(PropertiesOptionError, "api.option(path).value.append(first_value[0])") + raises(PropertiesOptionError, "api.option(path).value.set([first_value[0]])") elif isslave: raises(PropertiesOptionError, "api.option(path, 0).value.set(first_value[0])") else: @@ -180,31 +177,30 @@ def autocheck_value(api, path, **kwargs): if ismaster: raises(APIError, "api.unrestraint.option(path).value.set(second_value[1])") elif isslave: - raises(APIError, "api.unrestraint.option(path).value.append(second_value[1])") + raises(APIError, "api.unrestraint.option(path).value.set([first_value[0], second_value[1]])") else: raises(APIError, "api.unrestraint.option(path).value.set(second_value)") if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False): if ismaster: raises(APIError, "api.forcepermissive.option(path, 1).value.set(second_value[1])") - api.forcepermissive.option(path).value.append(second_value[1]) + api.forcepermissive.option(path).value.set([first_value[0], second_value[1]]) elif isslave: #FIXME - raises(PropertiesOptionError, "api.forcepermissive.option(path).value.append(second_value[1])") + raises(PropertiesOptionError, "api.forcepermissive.option(path).value.set([first_value[0], second_value[1]])") api.option(path, 1).value.set(second_value[1]) raise Exception('ca entre ici') else: api.option(path).value.set(second_value) elif kwargs.get('permissive', False): if ismaster: - api.forcepermissive.option(path).value.append(second_value[0]) - api.forcepermissive.option(path).value.append(second_value[1]) + api.forcepermissive.option(path).value.set([first_value[0], second_value[1]]) elif isslave: api.forcepermissive.option(path, 1).value.set(second_value[1]) else: api.forcepermissive.option(path).value.set(first_value) else: if ismaster: - raises(PropertiesOptionError, "api.forcepermissive.option(path).value.append(first_value[0])") + raises(PropertiesOptionError, "api.forcepermissive.option(path).value.set([first_value[0]])") elif isslave: raises(PropertiesOptionError, "api.forcepermissive.option(path, 0).value.set(first_value[0])") else: @@ -240,15 +236,8 @@ def autocheck_value(api, path, **kwargs): @autocheck def autocheck_reset_value(api, path, **kwargs): # check if is a multi, a master or a slave - if not kwargs.get('propertyerror', False): - multi = api.forcepermissive.option(path).option.ismulti() - ismaster = api.forcepermissive.option(path).option.ismaster() - isslave = api.forcepermissive.option(path).option.isslave() - else: - raises(PropertiesOptionError, "api.forcepermissive.option(path).option.ismulti()") - multi = api.unrestraint.option(path).option.ismulti() - ismaster = api.unrestraint.option(path).option.ismaster() - isslave = api.unrestraint.option(path).option.isslave() + multi = api.unrestraint.option(path).option.ismulti() + isslave = api.unrestraint.option(path).option.isslave() # set default value (different if value is multi or not) if not multi: @@ -337,14 +326,8 @@ def autocheck_property(api, path, **kwargs): """get property from path """ # check if is a multi or a slave - if not kwargs.get('propertyerror', False): - multi = api.forcepermissive.option(path).option.ismulti() - isslave = api.forcepermissive.option(path).option.isslave() - else: - raises(PropertiesOptionError, "api.forcepermissive.option(path).option.ismulti()") - raises(PropertiesOptionError, "api.forcepermissive.option(path).option.isslave()") - multi = api.unrestraint.option(path).option.ismulti() - isslave = api.unrestraint.option(path).option.isslave() + multi = api.unrestraint.option(path).option.ismulti() + isslave = api.unrestraint.option(path).option.isslave() # define properties properties = ['prop1', 'prop2'] @@ -367,7 +350,10 @@ def autocheck_property(api, path, **kwargs): assert set(api.option(path, 0).property.get()) == set(default_props) assert set(api.option(path, 1).property.get()) == set(default_props) else: - raises(PropertiesOptionError, "api.option(path).property.get()") + if not isslave: + raises(PropertiesOptionError, "api.option(path).property.get()") + else: + raises(PropertiesOptionError, "api.option(path, 0).property.get()") # get properties with permissive if not isslave: @@ -390,17 +376,21 @@ def autocheck_property(api, path, **kwargs): if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False): api.option(path).property.set(properties) else: - raises(PropertiesOptionError, "api.option(path).property.set(properties)") + if not isslave: + raises(PropertiesOptionError, "api.option(path).property.set(properties)") + else: + raises(PropertiesOptionError, "api.option(path, 0).property.set(properties)") # check properties after set without permissive if not kwargs.get('permissive', False) and not kwargs.get('propertyerror', False): assert set(api.option(path).property.get()) == set(properties) assert set(api.forcepermissive.option(path).property.get()) == set(properties) elif kwargs.get('permissive', False): - raises(PropertiesOptionError, "api.option(path).property.get()") if not isslave: + raises(PropertiesOptionError, "api.option(path).property.get()") assert set(api.forcepermissive.option(path).property.get()) == set(default_props) else: + raises(PropertiesOptionError, "api.option(path, 0).property.get()") assert set(api.forcepermissive.option(path, 0).property.get()) == set(default_props) assert set(api.forcepermissive.option(path, 1).property.get()) == set(default_props) else: @@ -588,7 +578,8 @@ def autocheck_owner_with_value(api, path, **kwargs): if not isslave: assert api.forcepermissive.option(path).owner.isdefault() is False else: - assert api.forcepermissive.option(path, 0).owner.isdefault() is False + assert api.forcepermissive.option(path, 0).owner.isdefault() is True + assert api.forcepermissive.option(path, 1).owner.isdefault() is False else: raises(PropertiesOptionError, "api.forcepermissive.option(path).owner.isdefault()") @@ -773,18 +764,15 @@ def check_all(api, path, multi, **kwargs): def make_api(options, multi): - def make_option(path): - option_infos = path.split('_') + def make_option(path, option_infos): + #FIXME option_type = 'str' option_properties = [] - for option_info in option_infos[1:]: - if option_info in OPTIONS_TYPE: - option_type = option_info - elif option_info in PROPERTIES: - option_properties.append(option_info) - else: - raise Exception('unknown {} in {}'.format(option_info, path)) - args = [option_infos[0], "{}'s option".format(option_infos[0])] + if option_infos is not None: + for prop in PROPERTIES: + if option_infos.get(prop, False) is True: + option_properties.append(prop) + args = [path, "{}'s option".format(path)] kwargs = {} if option_properties != []: kwargs['properties'] = tuple(option_properties) @@ -794,23 +782,21 @@ def make_api(options, multi): return tiramisu_option(*args, **kwargs) def make_optiondescriptions(path, collected): - infos = path.split('_') - name = infos[0] + infos = collected.get('properties', {}) properties = [] kwargs = {} optiondescription = OptionDescription - for info in infos[1:]: - if info in PROPERTIES: - properties.append(info) - elif info == 'master': - if not multi: - return - optiondescription = MasterSlaves - elif info == 'dyn': - optiondescription = DynOptionDescription - kwargs['callback'] = return_list - else: - raise Exception('unknown {} in {}'.format(info, path)) + + for prop in PROPERTIES: + if infos.get(prop, False) is True: + properties.append(prop) + if infos.get('master', False) is True: + if not multi: + return + optiondescription = MasterSlaves + if infos.get('dyn', False) is True: + optiondescription = DynOptionDescription + kwargs['callback'] = return_list options = [] if 'options' in collected: options.extend(collected['options']) @@ -823,19 +809,20 @@ def make_api(options, multi): options.append(option) if properties != []: kwargs['properties'] = tuple(properties) - return optiondescription(name, "{}'s optiondescription".format(name), options, **kwargs) + return optiondescription(path, "{}'s optiondescription".format(path), options, **kwargs) collect_options = {} - for option in options: + for path, option in options.items(): if option is None: continue local_collect_options = collect_options - for optiondescription in option.split('.')[:-1]: + for optiondescription in path.split('.')[:-1]: local_collect_options.setdefault(optiondescription, {}) local_collect_options = local_collect_options[optiondescription] - path = '.'.join(option.split('.')[:-1]) - option_name = option.split('.')[-1] - local_collect_options.setdefault("options", []).append(make_option(option_name)) + local_collect_options['properties'] = option.get(optiondescription, {}) + option_name = path.split('.')[-1] + path = '.'.join(path.split('.')[:-1]) + local_collect_options.setdefault('options', []).append(make_option(option_name, option.get(option_name))) rootod = make_optiondescriptions('root', collect_options) if rootod is None: @@ -846,39 +833,45 @@ def make_api(options, multi): DICT_PATHS = [ #test a config without optiondescription - OrderedDict([('first', 'first'), - ('second', 'second_disabled'), - ('third', 'third_hidden')]), + OrderedDict([('first', {}), + ('second', {'second': {'disabled': True}}), + ('third', {'third': {'hidden': True}})]), #test a config with an optiondescription - OrderedDict([('subod.first', 'subod.first'), - ('subod.second', 'subod.second_disabled'), - ('subod.third', 'subod.third_hidden')]), + OrderedDict([('subod.first', {}), + ('subod.second', {'second': {'disabled': True}}), + ('subod.third', {'third': {'hidden': True}})]), #test a config with two optiondescription - OrderedDict([('subod.subsubod.first', 'subod.subsubod.first'), - ('subod.subsubod.second', 'subod.subsubod.second_disabled'), - ('subod.subsubod.third', 'subod.subsubod.third_hidden')]), + OrderedDict([('subod.subsubod.first', {}), + ('subod.subsubod.second', {'second': {'disabled': True}}), + ('subod.subsubod.third', {'third': {'hidden': True}})]), #test a config with mix of different optiondescription - OrderedDict([('first', 'first'), - ('subod.second', 'subod.second_disabled'), - ('subod.subsubod.third', 'subod.subsubod.third_hidden')]), + OrderedDict([('first', {}), + ('subod.second', {'second': {'disabled': True}}), + ('subod.subsubod.third', {'third': {'hidden': True}})]), #test a config with masterslaves - OrderedDict([('first.first', 'first_master.first'), - ('first.second', 'first_master.second_disabled'), - ('first.third', 'first_master.third_hidden')]), + OrderedDict([('odmaster.first', {'odmaster': {'master': True}}), + ('odmaster.second', {'second': {'disabled': True}}), + ('odmaster.third', {'third': {'hidden': True}})]), ##test a config with dynoption - OrderedDict([('subodval1.firstval1', 'subod_dyn.first'), - ('subodval1.secondval1', 'subod_dyn.second_disabled'), - ('subodval1.thirdval1', 'subod_dyn.third_hidden'), + OrderedDict([('subod.firstv', {'subod': {'dyn': True}}), + ('subod.second', {'second': {'disabled': True}}), + ('subod.third', {'third': {'hidden': True}}), + ('subodval1.firstval1', None), + ('subodval1.secondval1', None), + ('subodval1.thirdval1', None), ('subodval2.firstval2', None), ('subodval2.secondval2', None), ('subodval2.thirdval2', None)]), #test a config with dynoption subdir - OrderedDict([('subod.subodval1.firstval1', 'subod.subod_dyn.first'), - ('subod.subodval1.secondval1', 'subod.subod_dyn.second_disabled'), - ('subod.subodval1.thirdval1', 'subod.subod_dyn.third_hidden'), - ('subod.subodval2.firstval2', None), - ('subod.subodval2.secondval2', None), - ('subod.subodval2.thirdval2', None)]) + OrderedDict([('subod.subsubod.first', {'subod': {'dyn': True}}), + ('subod.subsubod.second', {'second': {'disabled': True}}), + ('subod.subsubod.third', {'third': {'hidden': True}}), + ('subod.subsubodval1.firstval1', None), + ('subod.subsubodval1.secondval1', None), + ('subod.subsubodval1.thirdval1', None), + ('subod.subsubodval2.firstval2', None), + ('subod.subsubodval2.secondval2', None), + ('subod.subsubodval2.thirdval2', None)]) ] @@ -892,7 +885,7 @@ def paths(request): def test_options(paths): lpaths = list(paths.keys()) for multi in (False, True): - api = make_api(paths.values(), multi) + api = make_api(paths, multi) if api is None: continue check_all(api, lpaths[0], multi) @@ -908,15 +901,18 @@ def test_options(paths): DICT_PATHS2 = [ - OrderedDict([('subod.subsubod.first', 'subod.subsubod_hidden.first'), - ('subod.subsubod.second', 'subod.subsubod_hidden.second'), - ('subod.subsubod.third', 'subod.subsubod_hidden.third_hidden')]), - OrderedDict([('subod.subodval1.firstval1', 'subod.subod_dyn_hidden.first'), - ('subod.subodval1.secondval1', 'subod.subod_dyn_hidden.second'), - ('subod.subodval1.thirdval1', 'subod.subod_dyn_hidden.third_hidden'), - ('subod.subodval2.firstval2', None), - ('subod.subodval2.secondval2', None), - ('subod.subodval2.thirdval2', None)]) + OrderedDict([('subod.subsubod.first', {'subsubod': {'hidden': True}}), + ('subod.subsubod.second', {}), + ('subod.subsubod.third', {})]), + OrderedDict([('subod.subsubod.first', {'subsub': {'dyn': True, 'hidden': True}}), + ('subod.subsubod.second', {}), + ('subod.subsubod.third', {}), + ('subod.subsubodval1.firstval1', None), + ('subod.subsubodval1.secondval1', None), + ('subod.subsubodval1.thirdval1', None), + ('subod.subsubodval2.firstval2', None), + ('subod.subsubodval2.secondval2', None), + ('subod.subsubodval2.thirdval2', None)]) ] @@ -927,18 +923,19 @@ def paths2(request): return request.param -def test_tree_od_permissive(paths2): - """permissive when optiondescription is hidden - """ - lpaths = list(paths2.keys()) - for multi in (False, True): - api = make_api(paths2.values(), multi) - if api is None: - continue - check_all(api, lpaths[0], multi, permissive=True) - check_all(api, lpaths[1], multi, permissive=True) - check_all(api, lpaths[2], multi, permissive=True, extra_properties=['hidden']) - if len(lpaths) == 6: - check_all(api, lpaths[3], multi, permissive=True) - check_all(api, lpaths[4], multi, permissive=True) - check_all(api, lpaths[5], multi, permissive=True, extra_properties=['hidden']) +#FIXME +#def test_tree_od_permissive(paths2): +# """permissive when optiondescription is hidden +# """ +# lpaths = list(paths2.keys()) +# for multi in (False, True): +# api = make_api(paths2, multi) +# if api is None: +# continue +# check_all(api, lpaths[0], multi, permissive=True) +# check_all(api, lpaths[1], multi, permissive=True) +# check_all(api, lpaths[2], multi, permissive=True, extra_properties=['hidden']) +# if len(lpaths) == 6: +# check_all(api, lpaths[3], multi, permissive=True) +# check_all(api, lpaths[4], multi, permissive=True) +# check_all(api, lpaths[5], multi, permissive=True, extra_properties=['hidden']) diff --git a/test/test_multi.py b/test/test_multi.py index 276a025..d1b69fb 100644 --- a/test/test_multi.py +++ b/test/test_multi.py @@ -2,7 +2,7 @@ from .autopath import do_autopath do_autopath() -from tiramisu.value import Multi +#from tiramisu.value import Multi from tiramisu.option import IntOption, StrOption, OptionDescription from tiramisu.config import Config from tiramisu.error import ConfigError, PropertiesOptionError @@ -12,33 +12,6 @@ import weakref from py.test import raises -def test_multi(): - i = IntOption('int', '', multi=True) - o = OptionDescription('od', '', [i]) - c = Config(o) - multi = Multi([1, 2, 3], weakref.ref(c), i, 'int') - raises(ValueError, "Multi([1,2,3], c, i, 'int')") - raises(ValueError, "Multi(multi, weakref.ref(c), i, 'int')") - assert c is multi._getcontext() - del(c) - raises(ConfigError, "multi._getcontext()") - - -def test_multi_unique(): - i = IntOption('int', '', multi=True, unique=True) - o = OptionDescription('od', '', [i]) - c = Config(o) - assert c.int == [] - c.int = [0] - assert c.int == [0] - raises(ValueError, "c.int = [0, 0]") - raises(ValueError, "c.int = [1, 0, 2, 3, 4, 5, 6, 0, 7]") - raises(ValueError, "c.int.append(0)") - raises(ValueError, "c.int.extend([1, 2, 1, 3])") - raises(ValueError, "c.int.extend([1, 2, 0, 3])") - c.int.extend([4, 5, 6]) - - def test_non_valid_multi(): raises(ValueError, "IntOption('int', '', multi='string')") raises(ValueError, "IntOption('int', '', multi=True, unique='string')") @@ -46,21 +19,3 @@ def test_non_valid_multi(): def test_non_multi_unique(): raises(ValueError, "IntOption('int', '', unique=True)") - - -def test_multi_none(): - s = StrOption('str', '', multi=True) - o = OptionDescription('od', '', [s]) - c = Config(o) - c.read_only() - assert c.str == [] - c.read_write() - c.str.append(None) - assert c.str == [None] - c.read_only() - raises(PropertiesOptionError, "c.str") - c.read_write() - c.str = [''] - assert c.str == [''] - c.read_only() - raises(PropertiesOptionError, "c.str") diff --git a/test/test_submulti.py b/test/test_submulti.py index 37a12dc..bc8ab93 100644 --- a/test/test_submulti.py +++ b/test/test_submulti.py @@ -5,7 +5,7 @@ do_autopath() from tiramisu.setting import groups, owners from tiramisu.config import Config, MetaConfig from tiramisu.option import StrOption, IntOption, OptionDescription, submulti, MasterSlaves -from tiramisu.value import SubMulti, Multi +#from tiramisu.value import SubMulti, Multi from tiramisu.error import SlaveError from py.test import raises @@ -28,7 +28,7 @@ def return_list2(value=None): def test_submulti(): multi = StrOption('multi', '', multi=submulti) - multi2 = StrOption('multi2', '', default_multi='yes', multi=submulti) + multi2 = StrOption('multi2', '', default_multi=['yes'], multi=submulti) multi3 = StrOption('multi3', '', default=[['yes']], multi=submulti) od = OptionDescription('od', '', [multi, multi2, multi3]) cfg = Config(od) @@ -43,314 +43,6 @@ def test_submulti(): assert cfg.getowner(multi) == owners.default -def test_append_submulti(): - multi = StrOption('multi', '', multi=submulti) - multi2 = StrOption('multi2', '', default_multi='yes', multi=submulti) - multi3 = StrOption('multi3', '', default=[['yes']], multi=submulti) - od = OptionDescription('od', '', [multi, multi2, multi3]) - cfg = Config(od) - owner = cfg.cfgimpl_get_settings().getowner() - assert cfg.multi == [] - assert cfg.getowner(multi) == owners.default - cfg.multi.append() - assert cfg.getowner(multi) == owner - assert cfg.multi == [[]] - cfg.multi.append(['no']) - assert cfg.multi == [[], ['no']] - # - assert cfg.multi2 == [] - assert cfg.getowner(multi2) == owners.default - cfg.multi2.append() - assert cfg.getowner(multi2) == owner - assert cfg.multi2 == [['yes']] - cfg.multi2.append(['no']) - assert cfg.multi2 == [['yes'], ['no']] - # - assert cfg.multi3 == [['yes']] - assert cfg.getowner(multi3) == owners.default - cfg.multi3.append() - assert cfg.getowner(multi3) == owner - assert cfg.multi3 == [['yes'], []] - cfg.multi3.append(['no']) - assert cfg.multi3 == [['yes'], [], ['no']] - - -def test_append_unvalide_submulti(): - multi = StrOption('multi', '', multi=submulti) - multi2 = StrOption('multi2', '', default_multi='yes', multi=submulti) - multi3 = StrOption('multi3', '', default=[['yes']], multi=submulti) - od = OptionDescription('od', '', [multi, multi2, multi3]) - cfg = Config(od) - assert cfg.multi == [] - assert cfg.getowner(multi) == owners.default - raises(ValueError, "cfg.multi.append(1)") - assert cfg.multi == [] - assert cfg.getowner(multi) == owners.default - # - assert cfg.multi2 == [] - raises(ValueError, "cfg.multi2.append('no')") - assert cfg.getowner(multi) == owners.default - assert cfg.multi2 == [] - # - assert cfg.multi3 == [['yes']] - assert cfg.getowner(multi3) == owners.default - raises(ValueError, "cfg.multi3[0].append(1)") - assert cfg.multi3 == [['yes']] - assert cfg.getowner(multi3) == owners.default - raises(ValueError, "cfg.multi3[0].append([])") - assert cfg.multi3 == [['yes']] - assert cfg.getowner(multi3) == owners.default - - -def test_pop_submulti(): - multi = StrOption('multi', '', multi=submulti) - multi2 = StrOption('multi2', '', default_multi='yes', multi=submulti) - multi3 = StrOption('multi3', '', default=[['yes']], multi=submulti) - od = OptionDescription('od', '', [multi, multi2, multi3]) - cfg = Config(od) - owner = cfg.cfgimpl_get_settings().getowner() - assert cfg.multi == [] - assert cfg.getowner(multi3) == owners.default - cfg.multi = [['no', 'yes'], ['peharps']] - assert cfg.getowner(multi) == owner - assert cfg.multi == [['no', 'yes'], ['peharps']] - cfg.multi[0].pop(1) - assert cfg.multi == [['no'], ['peharps']] - cfg.multi[0].pop(0) - assert cfg.multi == [[], ['peharps']] - cfg.multi.pop(1) - assert cfg.multi == [[]] - cfg.multi.pop(0) - assert cfg.multi == [] - # - assert cfg.multi3 == [['yes']] - assert cfg.getowner(multi3) == owners.default - cfg.multi3.pop(0) - assert cfg.getowner(multi) == owner - assert cfg.multi3 == [] - del(cfg.multi3) - assert cfg.getowner(multi3) == owners.default - cfg.multi3[0].pop(0) - assert cfg.getowner(multi3) == owner - assert cfg.multi3 == [[]] - - -def test_sort_submulti(): - multi = StrOption('multi', '', multi=submulti) - multi2 = StrOption('multi2', '', default_multi='yes', multi=submulti) - multi3 = StrOption('multi3', '', default=[['yes']], multi=submulti) - od = OptionDescription('od', '', [multi, multi2, multi3]) - cfg = Config(od) - owner = cfg.cfgimpl_get_settings().getowner() - assert cfg.multi == [] - assert cfg.getowner(multi) == owners.default - cfg.multi.sort() - assert cfg.getowner(multi) == owner - cfg.multi = [['no', 'yes'], ['peharps']] - cfg.multi.sort() - assert cfg.multi == [['no', 'yes'], ['peharps']] - cfg.multi.sort(reverse=True) - assert cfg.multi == [['peharps'], ['no', 'yes']] - cfg.multi[1].sort(reverse=True) - assert cfg.multi == [['peharps'], ['yes', 'no']] - cfg.multi[1].sort() - assert cfg.multi == [['peharps'], ['no', 'yes']] - # - assert cfg.multi3 == [['yes']] - assert cfg.getowner(multi3) == owners.default - cfg.multi3.sort() - assert cfg.getowner(multi) == owner - assert cfg.multi3 == [['yes']] - del(cfg.multi3) - assert cfg.getowner(multi3) == owners.default - cfg.multi3[0].sort() - assert cfg.getowner(multi) == owner - assert cfg.multi3 == [['yes']] - - -def test_reverse_submulti(): - multi = StrOption('multi', '', multi=submulti) - multi2 = StrOption('multi2', '', default_multi='yes', multi=submulti) - multi3 = StrOption('multi3', '', default=[['yes']], multi=submulti) - od = OptionDescription('od', '', [multi, multi2, multi3]) - cfg = Config(od) - owner = cfg.cfgimpl_get_settings().getowner() - assert cfg.multi == [] - assert cfg.getowner(multi) == owners.default - cfg.multi.reverse() - assert cfg.getowner(multi) == owner - cfg.multi = [['no', 'yes'], ['peharps']] - cfg.multi.reverse() - assert cfg.multi == [['peharps'], ['no', 'yes']] - cfg.multi[1].reverse() - assert cfg.multi == [['peharps'], ['yes', 'no']] - # - assert cfg.multi3 == [['yes']] - assert cfg.getowner(multi3) == owners.default - cfg.multi3.reverse() - assert cfg.getowner(multi) == owner - assert cfg.multi3 == [['yes']] - del(cfg.multi3) - assert cfg.getowner(multi3) == owners.default - cfg.multi3[0].reverse() - assert cfg.getowner(multi) == owner - assert cfg.multi3 == [['yes']] - - -def test_insert_submulti(): - multi = StrOption('multi', '', multi=submulti) - multi2 = StrOption('multi2', '', default_multi='yes', multi=submulti) - multi3 = StrOption('multi3', '', default=[['yes']], multi=submulti) - od = OptionDescription('od', '', [multi, multi2, multi3]) - cfg = Config(od) - owner = cfg.cfgimpl_get_settings().getowner() - assert cfg.multi == [] - assert cfg.getowner(multi) == owners.default - cfg.multi.insert(0, ['no']) - assert cfg.getowner(multi) == owner - assert cfg.multi == [['no']] - assert isinstance(cfg.multi, Multi) - assert isinstance(cfg.multi[0], SubMulti) - # - assert cfg.multi3 == [['yes']] - assert cfg.getowner(multi3) == owners.default - cfg.multi3.insert(1, []) - assert cfg.getowner(multi3) == owner - assert cfg.multi3 == [['yes'], []] - cfg.multi3.insert(0, ['no']) - assert cfg.multi3 == [['no'], ['yes'], []] - del(cfg.multi3) - assert cfg.getowner(multi3) == owners.default - cfg.multi3[0].insert(0, 'no') - assert cfg.getowner(multi3) == owner - assert cfg.multi3 == [['no', 'yes']] - - -def test_insert_unvalide_submulti(): - multi = StrOption('multi', '', multi=submulti) - multi2 = StrOption('multi2', '', default_multi='yes', multi=submulti) - multi3 = StrOption('multi3', '', default=[['yes']], multi=submulti) - od = OptionDescription('od', '', [multi, multi2, multi3]) - cfg = Config(od) - assert cfg.multi == [] - assert cfg.getowner(multi) == owners.default - raises(ValueError, "cfg.multi.insert(0, 1)") - assert cfg.multi == [] - assert cfg.getowner(multi) == owners.default - # - assert cfg.multi3 == [['yes']] - assert cfg.getowner(multi3) == owners.default - raises(ValueError, "cfg.multi3[0].insert(0, 1)") - assert cfg.multi3 == [['yes']] - assert cfg.getowner(multi3) == owners.default - - -def test_extend_submulti(): - multi = StrOption('multi', '', multi=submulti) - multi2 = StrOption('multi2', '', default_multi='yes', multi=submulti) - multi3 = StrOption('multi3', '', default=[['yes']], multi=submulti) - od = OptionDescription('od', '', [multi, multi2, multi3]) - cfg = Config(od) - owner = cfg.cfgimpl_get_settings().getowner() - assert cfg.multi == [] - assert cfg.getowner(multi) == owners.default - cfg.multi.extend([['no']]) - assert cfg.getowner(multi) == owner - assert cfg.multi == [['no']] - assert isinstance(cfg.multi, Multi) - assert isinstance(cfg.multi[0], SubMulti) - # - assert cfg.multi3 == [['yes']] - assert cfg.getowner(multi3) == owners.default - cfg.multi3.extend([[]]) - assert cfg.getowner(multi3) == owner - assert cfg.multi3 == [['yes'], []] - cfg.multi3.extend([['no']]) - assert cfg.multi3 == [['yes'], [], ['no']] - del(cfg.multi3) - assert cfg.getowner(multi3) == owners.default - cfg.multi3[0].extend(['no']) - assert cfg.getowner(multi3) == owner - assert cfg.multi3 == [['yes', 'no']] - - -def test_extend_unvalide_submulti(): - multi = StrOption('multi', '', multi=submulti) - multi2 = StrOption('multi2', '', default_multi='yes', multi=submulti) - multi3 = StrOption('multi3', '', default=[['yes']], multi=submulti) - od = OptionDescription('od', '', [multi, multi2, multi3]) - cfg = Config(od) - assert cfg.multi == [] - assert cfg.getowner(multi) == owners.default - raises(ValueError, "cfg.multi.extend([[1]])") - assert cfg.multi == [] - assert cfg.getowner(multi) == owners.default - # - assert cfg.multi3 == [['yes']] - assert cfg.getowner(multi3) == owners.default - raises(ValueError, "cfg.multi3[0].extend([1])") - assert cfg.multi3 == [['yes']] - assert cfg.getowner(multi3) == owners.default - - -def test_callback_submulti_str(): - multi = StrOption('multi', '', multi=submulti, callback=return_val) - od = OptionDescription('od', '', [multi]) - cfg = Config(od) - cfg.read_write() - owner = cfg.cfgimpl_get_settings().getowner() - assert cfg.getowner(multi) == owners.default - assert cfg.multi == [['val']] - cfg.multi.append() - assert cfg.getowner(multi) == owner - assert cfg.multi == [['val'], ['val']] - del(cfg.multi) - assert cfg.getowner(multi) == owners.default - cfg.multi[0].append() - assert cfg.getowner(multi) == owner - assert cfg.multi == [['val', 'val']] - - -def test_callback_submulti_list(): - multi = StrOption('multi', '', multi=submulti, callback=return_list) - od = OptionDescription('od', '', [multi]) - cfg = Config(od) - cfg.read_write() - owner = cfg.cfgimpl_get_settings().getowner() - assert cfg.multi == [['val', 'val']] - assert cfg.getowner(multi) == owners.default - cfg.multi.append() - assert cfg.getowner(multi) == owner - assert cfg.multi == [['val', 'val'], ['val', 'val']] - cfg.multi.append() - assert cfg.multi == [['val', 'val'], ['val', 'val'], ['val', 'val']] - del(cfg.multi) - assert cfg.getowner(multi) == owners.default - cfg.multi[0].append() - assert cfg.getowner(multi) == owner - assert cfg.multi == [['val', 'val', None]] - - -def test_callback_submulti_list_list(): - multi = StrOption('multi', '', multi=submulti, callback=return_list2) - od = OptionDescription('od', '', [multi]) - cfg = Config(od) - cfg.read_write() - owner = cfg.cfgimpl_get_settings().getowner() - assert cfg.multi == [['val', 'val']] - assert cfg.getowner(multi) == owners.default - cfg.multi.append() - assert cfg.getowner(multi) == owner - assert cfg.multi == [['val', 'val'], []] - del(cfg.multi) - assert cfg.getowner(multi) == owners.default - cfg.multi[0].append() - assert cfg.getowner(multi) == owner - assert cfg.multi == [['val', 'val', None]] - del(cfg.multi) - cfg.multi.append() - - #FIXME multi sur une master @@ -371,35 +63,6 @@ def test_groups_with_master_in_config_submulti(): assert interface1.impl_get_group_type() == groups.master -def test_values_with_master_and_slaves_submulti(): - ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True) - netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=submulti) - interface1 = MasterSlaves('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0]) - #interface1.impl_set_group_type(groups.master) - maconfig = OptionDescription('toto', '', [interface1]) - cfg = Config(maconfig) - cfg.read_write() - owner = cfg.cfgimpl_get_settings().getowner() - assert interface1.impl_get_group_type() == groups.master - assert cfg.getowner(ip_admin_eth0) == owners.default - assert cfg.getowner(netmask_admin_eth0) == owners.default - assert cfg.ip_admin_eth0.netmask_admin_eth0 == [] - cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145") - assert cfg.ip_admin_eth0.ip_admin_eth0 == ["192.168.230.145"] - assert cfg.ip_admin_eth0.netmask_admin_eth0 == [[]] - assert cfg.getowner(ip_admin_eth0) == owner - assert cfg.getowner(netmask_admin_eth0) == owners.default - cfg.ip_admin_eth0.ip_admin_eth0 = ["192.168.230.145", "192.168.230.147"] - assert cfg.ip_admin_eth0.netmask_admin_eth0 == [[], []] - raises(SlaveError, 'cfg.ip_admin_eth0.netmask_admin_eth0.append(None)') - raises(SlaveError, 'cfg.ip_admin_eth0.netmask_admin_eth0.pop(0)') - cfg.ip_admin_eth0.netmask_admin_eth0[0].append('255.255.255.0') - assert cfg.ip_admin_eth0.netmask_admin_eth0 == [['255.255.255.0'], []] - cfg.ip_admin_eth0.netmask_admin_eth0[0].pop(0) - assert cfg.ip_admin_eth0.netmask_admin_eth0 == [[], []] - raises(ValueError, 'cfg.ip_admin_eth0.netmask_admin_eth0 = ["255.255.255.0", "255.255.255.0"]') - - def test_reset_values_with_master_and_slaves_submulti(): ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True) netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=submulti) @@ -663,54 +326,3 @@ def test_callback_submulti(): assert cfg.getowner(multi2) == owners.default assert cfg.multi == [['val']] assert cfg.multi2 == [['val']] - - -def test_submulti_unique(): - i = IntOption('int', '', multi=submulti, unique=True) - o = OptionDescription('od', '', [i]) - c = Config(o) - assert c.int == [] - c.int = [[0]] - assert c.int == [[0]] - raises(ValueError, "c.int = [[0, 0]]") - c.int = [[0], [0]] - raises(ValueError, "c.int[0] = [1, 0, 2, 3, 4, 5, 6, 0, 7]") - raises(ValueError, "c.int[0].append(0)") - raises(ValueError, "c.int[0].extend([1, 2, 1, 3])") - raises(ValueError, "c.int[0].extend([1, 2, 0, 3])") - c.int[0].extend([4, 5, 6]) - - -def test_multi_submulti_meta(): - multi = StrOption('multi', '', multi=submulti) - od = OptionDescription('od', '', [multi]) - conf1 = Config(od, session_id='conf1') - conf1.read_write() - conf2 = Config(od, session_id='conf2') - conf2.read_write() - meta = MetaConfig([conf1, conf2]) - meta.read_write() - meta.multi = [['val']] - assert meta.multi == [['val']] - multi = conf1.multi[0] - multi.append() - assert conf1.multi == [['val', None]] - assert meta.multi == [['val']] - - -def test_multi_submulti_meta_no_cache(): - multi = StrOption('multi', '', multi=submulti) - od = OptionDescription('od', '', [multi]) - conf1 = Config(od, session_id='conf1_1') - conf1.read_write() - conf2 = Config(od, session_id='conf2_1') - conf2.read_write() - meta = MetaConfig([conf1, conf2]) - meta.read_write() - meta.cfgimpl_get_settings().remove('cache') - meta.multi = [['val']] - assert meta.multi == [['val']] - multi = conf1.multi[0] - multi.append() - assert conf1.multi == [['val', None]] - assert meta.multi == [['val']] diff --git a/tiramisu/api.py b/tiramisu/api.py index c3e31c6..008c115 100644 --- a/tiramisu/api.py +++ b/tiramisu/api.py @@ -35,6 +35,7 @@ class CommonTiramisu(object): path, index, config, + setting_properties, force_permissive, force_unrestraint): self.opt = opt @@ -43,6 +44,7 @@ class CommonTiramisu(object): if self.slave_need_index: self._test_slave_index() self.config = config + self.setting_properties = setting_properties self.force_permissive = force_permissive self.force_unrestraint = force_unrestraint if not self.allow_unrestraint: @@ -81,11 +83,19 @@ class TiramisuOptionOption(CommonTiramisu): allow_unrestraint = True slave_need_index = False - def __init__(self, opt, path, index, config, force_permissive, force_unrestraint): + def __init__(self, + opt, + path, + index, + config, + setting_properties, + force_permissive, + force_unrestraint): super(TiramisuOptionOption, self).__init__(opt, path, index, config, + setting_properties, force_permissive, force_unrestraint) if config: @@ -117,11 +127,19 @@ class TiramisuOptionOption(CommonTiramisu): class TiramisuOptionOwner(CommonTiramisu): """manager option's owner""" - def __init__(self, opt, path, index, config, force_permissive, force_unrestraint): + def __init__(self, + opt, + path, + index, + config, + setting_properties, + force_permissive, + force_unrestraint): super(TiramisuOptionOwner, self).__init__(opt, path, index, config, + setting_properties, force_permissive, force_unrestraint) if config: @@ -135,9 +153,8 @@ class TiramisuOptionOwner(CommonTiramisu): def isdefault(self): """is option has defaut value""" - #FIXME isdefault for slave should have index! - #FIXME should not be here, just for check property return self.values.is_default_owner(self.opt, + index=self.index, force_permissive=self.force_permissive) def set(self, owner): @@ -158,11 +175,19 @@ class TiramisuOptionProperty(CommonTiramisu): #allow_unrestraint = True slave_need_index = False - def __init__(self, opt, path, index, config, force_permissive, force_unrestraint): + def __init__(self, + opt, + path, + index, + config, + setting_properties, + force_permissive, + force_unrestraint): super(TiramisuOptionProperty, self).__init__(opt, path, index, config, + setting_properties, force_permissive, force_unrestraint) if config: @@ -170,7 +195,10 @@ class TiramisuOptionProperty(CommonTiramisu): def get(self): self._test_slave_index() - return self.settings.getproperties(self.opt, self.path, index=self.index, obj=False) + return self.settings.getproperties(self.opt, + self.path, + index=self.index, + obj=False) def set(self, properties): """set properties for a specified option""" @@ -189,11 +217,19 @@ class TiramisuOptionPermissive(CommonTiramisu): allow_unrestraint = True slave_need_index = False - def __init__(self, opt, path, index, config, force_permissive, force_unrestraint): + def __init__(self, + opt, + path, + index, + config, + setting_properties, + force_permissive, + force_unrestraint): super(TiramisuOptionPermissive, self).__init__(opt, path, index, config, + setting_properties, force_permissive, force_unrestraint) if config: @@ -201,8 +237,7 @@ class TiramisuOptionPermissive(CommonTiramisu): def get(self): """get permissive value for a specified path""" - setting_properties = self.settings.getproperties(None, None, obj=False) - return self.settings.getpermissive(setting_properties, self.path) + return self.settings.getpermissive(self.setting_properties, self.path) def set(self, permissive): self.settings.setpermissive(permissive, opt=self.opt, path=self.path) @@ -217,25 +252,28 @@ class TiramisuOptionPermissive(CommonTiramisu): class TiramisuOptionValue(CommonTiramisu): """manager option's value""" - def __init__(self, opt, path, index, config, force_permissive, force_unrestraint): + def __init__(self, + opt, + path, + index, + config, + setting_properties, + force_permissive, + force_unrestraint): + super(TiramisuOptionValue, self).__init__(opt, path, index, config, + setting_properties, force_permissive, force_unrestraint) - def append(self, value=undefined): - if not self.opt.impl_is_master_slaves('master'): - raise APIError('append is only allowed for a master') - multi = self.config.getattr(self.path, - force_permissive=self.force_permissive) - multi.append(value) - self.set(multi) - def get(self): + settings = self.config.cfgimpl_get_settings() value = self.config.getattr(self.path, index=self.index, + setting_properties=self.setting_properties, force_permissive=self.force_permissive) if isinstance(value, Multi): value = list(value) @@ -247,45 +285,53 @@ class TiramisuOptionValue(CommonTiramisu): if isinstance(value, list): while undefined in value: idx = value.index(undefined) - value[idx] = values._getdefaultvalue(self.opt, - self.path, - True, - idx, - undefined, - True) + value[idx] = values.getdefaultvalue(self.opt, + self.path, + idx) else: if value == undefined: - value = values._getdefaultvalue(self.opt, - self.path, - True, - self.index, - undefined, - True) + value = values.getdefaultvalue(self.opt, + self.path, + self.index) self.config.setattr(self.path, value, index=self.index, force_permissive=self.force_permissive) + def pop(self, index): + """pop value for a specified master values + """ + self.config.delattr(self.path, + index=index, + setting_properties=self.setting_properties, + force_permissive=self.force_permissive) + def reset(self): """reset value for a value""" - if self.index is None: - self.config.cfgimpl_get_values().reset(self.opt, - path=self.path, - force_permissive=self.force_permissive) - else: - #FIXME ... _p_ ... - self.config.cfgimpl_get_values()._p_.resetvalue_index(self.path, self.index) + self.config.delattr(self.path, + index=self.index, + setting_properties=self.setting_properties, + force_permissive=self.force_permissive) class TiramisuOption(object): icon = '\u2937' tmpl_help = ' {} {}: {}' - def __init__(self, opt, path, index, config, force_permissive=False, force_unrestraint=False): + def __init__(self, + opt, + path, + index, + config, + setting_properties, + force_permissive, + force_unrestraint): + self.opt = opt self.path = path self.index = index self.config = config + self.setting_properties = setting_properties self.force_permissive = force_permissive self.force_unrestraint = force_unrestraint self.registers = {} @@ -310,6 +356,7 @@ class TiramisuOption(object): self.path, self.index, self.config, + self.setting_properties, self.force_permissive, self.force_unrestraint) elif subfunc == 'help': @@ -322,18 +369,25 @@ class TiramisuAPI(object): icon = '\u2937' tmpl_help = ' {} {}: {}' - def __init__(self, config, force_permissive=False, force_unrestraint=False): + def __init__(self, + config, + force_permissive=False, + force_unrestraint=False): self.config = config self.force_permissive = force_permissive self.force_unrestraint = force_unrestraint + settings = self.config.cfgimpl_get_settings() #FIXME ? self.config.read_write() - self.config.cfgimpl_get_settings().setpermissive(('hidden',)) + settings.setpermissive(('hidden',)) #/FIXME ? def option(self, path, index=None): validate = not self.force_unrestraint + settings = self.config.cfgimpl_get_settings() + setting_properties = settings.getcontextproperties() opt = self.config.unwrap_from_path(path, + setting_properties=setting_properties, validate=validate, validate_properties=validate, force_permissive=self.force_permissive, @@ -344,14 +398,19 @@ class TiramisuAPI(object): path, index, self.config, - force_permissive=self.force_permissive, - force_unrestraint=self.force_unrestraint) + setting_properties, + self.force_permissive, + self.force_unrestraint) def __getattr__(self, subfunc): if subfunc == 'forcepermissive': - return TiramisuAPI(self.config, force_permissive=True, force_unrestraint=self.force_unrestraint) + return TiramisuAPI(self.config, + force_permissive=True, + force_unrestraint=self.force_unrestraint) elif subfunc == 'unrestraint': - return TiramisuAPI(self.config, force_permissive=self.force_permissive, force_unrestraint=True) + return TiramisuAPI(self.config, + force_permissive=self.force_permissive, + force_unrestraint=True) elif subfunc == 'help': return self._help() else: diff --git a/tiramisu/config.py b/tiramisu/config.py index 19dda72..75fdbfa 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -31,7 +31,7 @@ from .option import OptionDescription, Option, SymLinkOption, \ from .option.baseoption import valid_name from .setting import groups, Settings, default_encoding, undefined from .storage import get_storages, set_storage, get_default_values_storages -from .value import Values, Multi +from .value import Values # , Multi from .i18n import _ @@ -45,9 +45,19 @@ class SubConfig(object): on-demand. A Config is also a SubConfig. Root Config is call context below """ - __slots__ = ('_impl_context', '_impl_descr', '_impl_path') + __slots__ = ('_impl_context', + '_impl_descr', + '_impl_path', + '_impl_setting_properties', + '_impl_length') - def __init__(self, descr, context, subpath=None): + def __init__(self, + descr, + context, + setting_properties, + validate, + force_permissive, + subpath=None): """ Configuration option management master class :param descr: describes the configuration schema @@ -63,13 +73,19 @@ class SubConfig(object): error = True if error: raise TypeError(_('descr must be an optiondescription, not {0}' - ).format(type(descr))) + ).format(type(descr))) self._impl_descr = descr # sub option descriptions if not isinstance(context, weakref.ReferenceType): # pragma: optional cover raise ValueError('context must be a Weakref') self._impl_context = context self._impl_path = subpath + if setting_properties is not undefined: + self._impl_setting_properties = setting_properties + if descr.impl_get_group_type() == groups.master: + self._impl_length = descr.get_length(context().cfgimpl_get_values(), + validate=validate, + force_permissive=force_permissive) def cfgimpl_reset_cache(self, only_expired=False, @@ -144,17 +160,20 @@ class SubConfig(object): else: reset_all_cache() - def cfgimpl_get_home_by_path(self, path, force_permissive=False, - returns_raise=False, _setting_properties=undefined, - validate_properties=True): + def cfgimpl_get_home_by_path(self, + path, + setting_properties, + validate_properties=True, + force_permissive=False, + returns_raise=False): """:returns: tuple (config, name)""" path = path.split('.') for step in path[:-1]: self = self.getattr(step, force_permissive=force_permissive, - returns_raise=returns_raise, validate_properties=validate_properties, - _setting_properties=_setting_properties) + returns_raise=returns_raise, + setting_properties=setting_properties) if isinstance(self, Exception): return self, None return self, path[-1] @@ -269,62 +288,111 @@ class SubConfig(object): # attribute methods def __setattr__(self, name, value): "attribute notation mechanism for the setting of the value of an option" - self.setattr(name, value) + self.setattr(name, + value) - def _setattr(self, name, value, force_permissive=False, not_raises=False): - """use setattr instead of _setattr - """ - self.setattr(name, value, force_permissive=force_permissive, - not_raises=not_raises) + def setattr(self, + name, + value, + force_permissive=False, + not_raises=False, + index=None, + setting_properties=undefined, + _commit=True): - def setattr(self, name, value, force_permissive=False, not_raises=False, index=None, - _setting_properties=undefined, _commit=True): if name.startswith('_impl_'): - return object.__setattr__(self, name, value) + return object.__setattr__(self, + name, + value) context = self._cfgimpl_get_context() - if _setting_properties is undefined: - _setting_properties = context.cfgimpl_get_settings()._getproperties(read_write=True) + if setting_properties is undefined: + setting_properties = context.cfgimpl_get_settings()._getproperties(read_write=True) if '.' in name: # pragma: optional cover - homeconfig, name = self.cfgimpl_get_home_by_path(name, - force_permissive=force_permissive, - _setting_properties=_setting_properties) - return homeconfig.setattr(name, value, force_permissive, - not_raises, index=index, - _setting_properties=_setting_properties, - _commit=_commit) + self, name = self.cfgimpl_get_home_by_path(name, + force_permissive=force_permissive, + setting_properties=setting_properties) child = self.cfgimpl_get_description().__getattr__(name, context=context) - if isinstance(child, OptionDescription) or isinstance(child, SynDynOptionDescription): + if isinstance(child, (OptionDescription, SynDynOptionDescription)): raise TypeError(_("can't assign to an OptionDescription")) # pragma: optional cover elif child._is_symlinkoption() and \ not isinstance(child, DynSymLinkOption): # pragma: no dynoptiondescription cover - path = context.cfgimpl_get_description().impl_get_path_by_opt( - child._impl_getopt()) - context.setattr(path, value, force_permissive, not_raises, index=index, - _setting_properties=_setting_properties, - _commit=_commit) + raise TypeError(_("can't assign to a SymlinkOption")) else: + msg = self.cfgimpl_get_description().impl_validate_value(child, value, self) + if msg is not None: + if not_raises: + return msg + else: + raise msg subpath = self._get_subpath(name) - ret = self.cfgimpl_get_values().setitem(child, value, subpath, - force_permissive=force_permissive, - not_raises=not_raises, index=index, - _setting_properties=_setting_properties, - _commit=_commit) - if ret is not None: - return ret + return self.cfgimpl_get_values().setitem(child, + value, + subpath, + force_permissive, + not_raises, + index, + setting_properties, + _commit) def __delattr__(self, name): + self.delattr(name) + + def delattr(self, + name, + index=None, + force_permissive=False, + setting_properties=undefined, + validate=True, + not_raises=False): context = self._cfgimpl_get_context() - child = self.cfgimpl_get_description().__getattr__(name, context) - self.cfgimpl_get_values().__delitem__(child) + if setting_properties is undefined: + setting_properties = context.cfgimpl_get_settings()._getproperties(read_write=True) + if '.' in name: # pragma: optional cover + self, name = self.cfgimpl_get_home_by_path(name, + force_permissive=force_permissive, + setting_properties=setting_properties) + child = self.cfgimpl_get_description().__getattr__(name, + context=context) + if isinstance(child, (OptionDescription, SynDynOptionDescription)): + raise TypeError(_("can't delete an OptionDescription")) # pragma: optional cover + elif child._is_symlinkoption() and \ + not isinstance(child, DynSymLinkOption): # pragma: no dynoptiondescription cover + raise TypeError(_("can't delete a SymlinkOption")) + else: + subpath = self._get_subpath(name) + values = self.cfgimpl_get_values() + if index is not None: + if child.impl_is_master_slaves('master'): + ret = values.reset_master(self, + child, + subpath, + index, + force_permissive, + setting_properties) + elif child.impl_is_master_slaves('slave'): + ret = values.reset_slave(child, + subpath, + index, + setting_properties, + force_permissive=force_permissive, + validate=validate) + else: + raise ValueError(_("can delete value with index only with a master or a slave")) + else: + ret = values.reset(child, + subpath, + setting_properties, + force_permissive=force_permissive, + validate=validate) + if ret: + if not_raises: + return ret + raise ret def __getattr__(self, name): - return self.getattr(name) - - def _getattr(self, name, force_permissive=False, validate=True): # pragma: optional cover - """use getattr instead of _getattr - """ - return self.getattr(name, force_permissive, validate) + setting_properties = self.cfgimpl_get_context().cfgimpl_get_settings().getcontextproperties() + return self.getattr(name, setting_properties) def _get_subpath(self, name): if self._impl_path is None: @@ -333,10 +401,15 @@ class SubConfig(object): subpath = self._impl_path + '.' + name return subpath - def getattr(self, name, force_permissive=False, validate=True, - _setting_properties=undefined, _self_properties=undefined, index=None, - returns_raise=False, returns_option=False, - validate_properties=True): + def getattr(self, + name, + setting_properties, + force_permissive=False, + validate=True, + validate_properties=True, + index=None, + returns_raise=False, + returns_option=False): """ attribute notation mechanism for accessing the value of an option :param name: attribute name @@ -346,51 +419,51 @@ class SubConfig(object): # attribute access by passing a path, # for instance getattr(self, "creole.general.family.adresse_ip_eth0") context = self._cfgimpl_get_context() - if _setting_properties is undefined: - _setting_properties = context.cfgimpl_get_settings()._getproperties(read_write=True) if '.' in name: - homeconfig, name = self.cfgimpl_get_home_by_path( - name, force_permissive=force_permissive, - validate_properties=validate_properties, - returns_raise=returns_raise, _setting_properties=_setting_properties) + homeconfig, name = self.cfgimpl_get_home_by_path(name, + force_permissive=force_permissive, + validate_properties=validate_properties, + returns_raise=returns_raise, + setting_properties=setting_properties) if isinstance(homeconfig, Exception): cfg = homeconfig else: - cfg = homeconfig.getattr(name, force_permissive=force_permissive, + cfg = homeconfig.getattr(name, + force_permissive=force_permissive, validate=validate, - _setting_properties=_setting_properties, - _self_properties=_self_properties, - index=index, returns_raise=returns_raise, - validate_properties=validate_properties) + validate_properties=validate_properties, + setting_properties=setting_properties, + index=index, + returns_raise=returns_raise) else: option = self.cfgimpl_get_description().__getattr__(name, context=context) subpath = self._get_subpath(name) if isinstance(option, DynSymLinkOption): - cfg = self.cfgimpl_get_values()._get_cached_value( - option, path=subpath, - validate=validate, - force_permissive=force_permissive, - setting_properties=_setting_properties, - self_properties=_self_properties, - validate_properties=validate_properties, - index=index) + cfg = self.cfgimpl_get_values().get_cached_value(option, + path=subpath, + validate=validate, + validate_properties=validate_properties, + force_permissive=force_permissive, + setting_properties=setting_properties, + index=index) elif option._is_symlinkoption(): # pragma: no dynoptiondescription cover - path = context.cfgimpl_get_description().impl_get_path_by_opt( - option._impl_getopt()) - cfg = context.getattr(path, validate=validate, - force_permissive=force_permissive, - _setting_properties=_setting_properties, - _self_properties=_self_properties, + path = context.cfgimpl_get_description().impl_get_path_by_opt(option._impl_getopt()) + cfg = context.getattr(path, + validate=validate, validate_properties=validate_properties, - index=index, returns_raise=True) + force_permissive=force_permissive, + setting_properties=setting_properties, + index=index, + returns_raise=True) elif option.impl_is_optiondescription(): - if validate_properties: - props = self.cfgimpl_get_settings().validate_properties( - option, True, False, path=subpath, - force_permissive=force_permissive, - self_properties=_self_properties, - setting_properties=_setting_properties) + if setting_properties: + props = self.cfgimpl_get_settings().validate_properties(option, + True, + False, + path=subpath, + force_permissive=force_permissive, + setting_properties=setting_properties) if props: if returns_raise: return props @@ -398,25 +471,29 @@ class SubConfig(object): raise props if returns_option is True: return option - return SubConfig(option, self._impl_context, subpath) + return SubConfig(option, + self._impl_context, + setting_properties, + validate, + force_permissive, + subpath) else: if validate: ret = self.cfgimpl_get_description().impl_validate(context, force_permissive, - _setting_properties) + setting_properties) if ret: if returns_raise: return ret else: raise ret - cfg = self.cfgimpl_get_values()._get_cached_value( - option, path=subpath, - validate=validate, - force_permissive=force_permissive, - setting_properties=_setting_properties, - self_properties=_self_properties, - validate_properties=validate_properties, - index=index) + cfg = self.cfgimpl_get_values().get_cached_value(option, + path=subpath, + validate=validate, + validate_properties=validate_properties, + force_permissive=force_permissive, + setting_properties=setting_properties, + index=index) if not returns_raise and isinstance(cfg, Exception): raise cfg if returns_option is True: @@ -473,13 +550,13 @@ class SubConfig(object): if byvalue is undefined: return True value = self.getattr(path, force_permissive=force_permissive, - _setting_properties=setting_properties, + setting_properties=setting_properties, returns_raise=True) if isinstance(value, Exception): if isinstance(value, PropertiesOptionError): return False raise value # pragma: no cover - elif isinstance(value, Multi): + elif isinstance(value, list): return byvalue in value else: return value == byvalue @@ -506,7 +583,7 @@ class SubConfig(object): if byvalue is undefined and check_properties: value = self.getattr(path, force_permissive=force_permissive, - _setting_properties=setting_properties, + setting_properties=setting_properties, returns_raise=True) if isinstance(value, Exception): if isinstance(value, PropertiesOptionError): @@ -533,9 +610,14 @@ class SubConfig(object): else: return find_results - def make_dict(self, flatten=False, _currpath=None, withoption=None, - withvalue=undefined, force_permissive=False, - setting_properties=undefined, fullpath=False): + def make_dict(self, + flatten=False, + _currpath=None, + withoption=None, + withvalue=undefined, + force_permissive=False, + setting_properties=undefined, + fullpath=False): """exports the whole config into a `dict`, for example: >>> print cfg.make_dict() @@ -579,17 +661,20 @@ class SubConfig(object): raise ValueError(_("make_dict can't filtering with value without " "option")) if setting_properties is undefined: - setting_properties = self.cfgimpl_get_settings()._getproperties( - read_write=False) + setting_properties = self.cfgimpl_get_settings()._getproperties(read_write=False) if withoption is not None: 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), + 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, setting_properties=setting_properties): path = '.'.join(path.split('.')[:-1]) - opt = context.unwrap_from_path(path, force_permissive=True) + opt = context.unwrap_from_path(path, + orce_permissive=True) mypath = self.cfgimpl_get_path() if mypath is not None: if mypath == path: @@ -624,7 +709,7 @@ class SubConfig(object): setting_properties, force_permissive=False, fullpath=False): value = self.getattr(path, force_permissive=force_permissive, - _setting_properties=setting_properties, + setting_properties=setting_properties, returns_raise=True) if isinstance(value, Exception): if not isinstance(value, PropertiesOptionError): # pragma: no cover @@ -689,30 +774,52 @@ class _CommonConfig(SubConfig): return self.cfgimpl_get_values().getowner(opt, index=index, force_permissive=force_permissive) - def unwrap_from_path(self, path, force_permissive=False, index=None, - validate_properties=True, validate=True, - _setting_properties=undefined): + def unwrap_from_path(self, + path, + setting_properties=undefined, + force_permissive=False, + index=None, + validate=True, + validate_properties=True): """convenience method to extract and Option() object from the Config() and it is **fast**: finds the option directly in the appropriate namespace :returns: Option() """ - if _setting_properties is undefined: - context = self._cfgimpl_get_context() - _setting_properties = context.cfgimpl_get_settings()._getproperties(read_write=True) if '.' in path: self, path = self.cfgimpl_get_home_by_path(path, - validate_properties=validate_properties, force_permissive=force_permissive, - _setting_properties=_setting_properties) - return self.getattr(path, - validate_properties=validate_properties, - validate=validate, - force_permissive=force_permissive, - index=index, - _setting_properties=_setting_properties, - returns_option=True) + validate_properties=validate_properties, + setting_properties=setting_properties) + if not validate_properties: + return self.cfgimpl_get_description().__getattr__(path, + context=self._cfgimpl_get_context()) + else: + option = self.cfgimpl_get_description().__getattr__(path, + context=self._cfgimpl_get_context()) + if not validate_properties: + return option + else: + if index is None and option.impl_is_master_slaves('slave'): + subpath = self._get_subpath(path) + props = self.cfgimpl_get_settings().validate_properties(option, + True, + False, + path=subpath, + force_permissive=force_permissive, + setting_properties=setting_properties) + if props: + raise props + return option + else: + return self.getattr(path, + validate=validate, + force_permissive=force_permissive, + index=index, + setting_properties=setting_properties, + validate_properties=validate_properties, + returns_option=True) def cfgimpl_get_path(self, dyn=True): return None @@ -743,19 +850,17 @@ class _CommonConfig(SubConfig): def __getstate__(self): raise NotImplementedError() - def _gen_fake_values(self, session): + def _gen_fake_values(self): fake_config = Config(self._impl_descr, persistent=False, force_values=get_default_values_storages(), force_settings=self.cfgimpl_get_settings()) - fake_config.cfgimpl_get_values()._p_.importation(self.cfgimpl_get_values()._p_.exportation(session, fake=True)) + fake_config.cfgimpl_get_values()._p_.importation(self.cfgimpl_get_values()._p_.exportation(fake=True)) return fake_config def duplicate(self, force_values=None, force_settings=None): config = Config(self._impl_descr, _duplicate=True, force_values=force_values, force_settings=force_settings) - session = self.cfgimpl_get_values()._p_.getsession() - config.cfgimpl_get_values()._p_.importation(self.cfgimpl_get_values()._p_.exportation( - session)) + config.cfgimpl_get_values()._p_.importation(self.cfgimpl_get_values()._p_.exportation()) config.cfgimpl_get_settings()._p_.set_modified_properties(self.cfgimpl_get_settings( )._p_.get_modified_properties()) config.cfgimpl_get_settings()._pp_.set_modified_permissives(self.cfgimpl_get_settings( @@ -795,7 +900,7 @@ class Config(_CommonConfig): raise ValueError(_("invalid session ID: {0} for config").format(session_id)) self._impl_settings = Settings(self, properties, permissives) self._impl_values = Values(self, values) - super(Config, self).__init__(descr, weakref.ref(self)) + super(Config, self).__init__(descr, weakref.ref(self), undefined, True, False) self._impl_meta = None #undocumented option used only in test script self._impl_test = False @@ -926,21 +1031,25 @@ class GroupConfig(_CommonConfig): __repr__ = __str__ - def getattr(self, name, force_permissive=False, validate=True, - _setting_properties=undefined, _self_properties=undefined, index=None, - returns_raise=False, returns_option=False, - validate_properties=True): + def getattr(self, + name, + setting_properties, + force_permissive=False, + validate=True, + index=None, + returns_raise=False, + validate_properties=True, + returns_option=False): for child in self._impl_children: if name == child._impl_name: return child return super(GroupConfig, self).getattr(name, force_permissive, validate, - _self_properties=_self_properties, index=index, - _setting_properties=_setting_properties, + setting_properties=setting_properties, returns_raise=returns_raise, - returns_option=False, - validate_properties=validate_properties) + validate_properties=validate_properties, + returns_option=False) class MetaConfig(GroupConfig): @@ -1000,22 +1109,30 @@ class MetaConfig(GroupConfig): else: child_value = child.getattr(path) if force_default or value == child_value: - child.cfgimpl_get_values().reset(opt, path=path, + child.cfgimpl_get_values().reset(opt, + path, + setting_properties, validate=False, - _setting_properties=setting_properties, _commit=False) continue if force_dont_change_value: - child_value = child.getattr(path, _setting_properties=setting_properties, + child_value = child.getattr(path, + setting_properties=setting_properties, returns_raise=True) if isinstance(child_value, Exception): ret.append(child_value) elif value != child_value: - childret = child.setattr(path, child_value, _commit=False, not_raises=True) + childret = child.setattr(path, + child_value, + _commit=False, + not_raises=True) if childret is not None: # pragma: no cover ret.append(childret) - setret = self.setattr(path, value, _commit=_commit, not_raises=True) + setret = self.setattr(path, + value, + _commit=_commit, + not_raises=True) if setret is not None: ret.append(setret) return ret @@ -1024,13 +1141,15 @@ class MetaConfig(GroupConfig): opt = self.cfgimpl_get_description().impl_get_opt_by_path(path) setting_properties = self.cfgimpl_get_settings()._getproperties(read_write=False) for child in self._impl_children: - child.cfgimpl_get_values().reset(opt, path=path, + child.cfgimpl_get_values().reset(opt, + path, + setting_properties, validate=False, - _setting_properties=setting_properties, _commit=False) - self.cfgimpl_get_values().reset(opt, path=path, - validate=False, - _setting_properties=setting_properties) + self.cfgimpl_get_values().reset(opt, + path, + setting_properties, + validate=False) def new_config(self, session_id, persistent=False): config = Config(self._impl_descr, session_id=session_id, diff --git a/tiramisu/option/baseoption.py b/tiramisu/option/baseoption.py index e50f298..b070070 100644 --- a/tiramisu/option/baseoption.py +++ b/tiramisu/option/baseoption.py @@ -135,7 +135,7 @@ class Base(object): def __init__(self, name, doc, requires=None, properties=None, is_multi=False): if not valid_name(name): - raise ValueError(_("invalid name: {0} for option").format(name)) + raise ValueError(_('invalid name: "{0}" for option').format(name)) if requires is not None: calc_properties, requires = validate_requires_arg(self, is_multi, requires, name) @@ -654,13 +654,18 @@ class DynSymLinkOption(object): else: return base_path + '.' + self._dyn - def impl_validate(self, value, context=undefined, validate=True, - force_index=None, force_submulti_index=None, is_multi=None, - display_error=True, display_warnings=True, multi=None, + def impl_validate(self, + value, + context=undefined, + validate=True, + force_index=None, + is_multi=None, + display_error=True, + display_warnings=True, + multi=None, setting_properties=undefined): return self._impl_getopt().impl_validate(value, context, validate, force_index, - force_submulti_index, current_opt=self, is_multi=is_multi, display_error=display_error, diff --git a/tiramisu/option/option.py b/tiramisu/option/option.py index 991904e..6b81fca 100644 --- a/tiramisu/option/option.py +++ b/tiramisu/option/option.py @@ -112,12 +112,23 @@ class Option(OnlyOption): super(Option, self).__init__(name, doc, requires=requires, properties=properties, is_multi=is_multi) if is_multi and default_multi is not None: - err = self._validate(default_multi) - if err: - raise ValueError(_("invalid default_multi value {0} " - "for option {1}: {2}").format( - str(default_multi), - self.impl_getname(), str(err))) + def test_multi_value(value): + err = self._validate(value) + if err: + raise ValueError(_("invalid default_multi value {0} " + "for option {1}: {2}").format( + str(value), + self.impl_getname(), str(err))) + if _multi is submulti: + if not isinstance(default_multi, list): + raise ValueError(_("invalid default_multi value {0} " + "for option {1}: must be a list for a submulti").format( + str(default_multi), + self.impl_getname())) + for value in default_multi: + test_multi_value(value) + else: + test_multi_value(default_multi) _setattr(self, '_default_multi', default_multi) if unique is not undefined: _setattr(self, '_unique', unique) @@ -239,10 +250,17 @@ class Option(OnlyOption): ret_val = val return ret_val - def impl_validate(self, value, context=undefined, validate=True, - force_index=None, force_submulti_index=None, - current_opt=undefined, is_multi=None, - display_error=True, display_warnings=True, multi=None, + def impl_validate(self, + value, + context=undefined, + validate=True, + force_index=None, + force_submulti_index=None, + current_opt=undefined, + is_multi=None, + display_error=True, + display_warnings=True, + multi=None, setting_properties=undefined): """ :param value: the option's value @@ -290,7 +308,8 @@ class Option(OnlyOption): else: validator_params_ = {'': (val,)} # Raise ValueError if not valid - value = carry_out_calculation(current_opt, context=context, + value = carry_out_calculation(current_opt, + context=context, callback=validator, callback_params=validator_params_, index=_index, @@ -304,11 +323,14 @@ class Option(OnlyOption): else: if display_error: # option validation - err = self._validate(_value, context, current_opt) + err = self._validate(_value, + context, + current_opt) if err: if debug: # pragma: no cover log.debug('do_validation: value: {0}, index: {1}, ' - 'submulti_index: {2}'.format(_value, _index, + 'submulti_index: {2}'.format(_value, + _index, submulti_index), exc_info=True) err_msg = '{0}'.format(err) @@ -342,8 +364,12 @@ class Option(OnlyOption): if error is None: # if context launch consistency validation #if context is not undefined: - ret = self._valid_consistency(current_opt, _value, context, - _index, submulti_index, display_warnings, + ret = self._valid_consistency(current_opt, + _value, + context, + _index, + submulti_index, + display_warnings, display_error) if isinstance(ret, ValueError): error = ret @@ -421,8 +447,13 @@ class Option(OnlyOption): err = do_validation(val, idx, force_submulti_index) if err: return err - return self._valid_consistency(current_opt, None, context, - None, None, display_warnings, display_error) + return self._valid_consistency(current_opt, + None, + context, + None, + None, + display_warnings, + display_error) def impl_is_dynsymlinkoption(self): return False @@ -596,7 +627,11 @@ class Option(OnlyOption): def impl_getdefault_multi(self): "accessing the default value for a multi" - return getattr(self, '_default_multi', None) + if self.impl_is_submulti(): + default_value = [] + else: + default_value = None + return getattr(self, '_default_multi', default_value) def _validate_callback(self, callback, callback_params): """callback_params: @@ -605,7 +640,7 @@ class Option(OnlyOption): """ if callback is None: return - default_multi = self.impl_getdefault_multi() + default_multi = getattr(self, '_default_multi', None) is_multi = self.impl_is_multi() default = self.impl_getdefault() if (not is_multi and (default is not None or default_multi is not None)) or \ diff --git a/tiramisu/option/optiondescription.py b/tiramisu/option/optiondescription.py index 1aede43..c899f25 100644 --- a/tiramisu/option/optiondescription.py +++ b/tiramisu/option/optiondescription.py @@ -163,11 +163,11 @@ class CacheOptionDescription(BaseOption): raise ConfigError(_('a dynoption ({0}) cannot have ' 'force_store_value property').format(subpath)) if force_store_values and not config._impl_values._p_.hasvalue(subpath, session): - value = config.cfgimpl_get_values()._get_cached_value(option, - path=subpath, - validate=False, - trusted_cached_properties=False, - validate_properties=True) + value = config.cfgimpl_get_values().get_cached_value(option, + path=subpath, + validate=False, + trusted_cached_properties=False, + validate_properties=True) value_set = True config._impl_values._p_.setvalue(subpath, value, owners.forced, None, session, False) @@ -497,6 +497,9 @@ class OptionDescription(OptionDescriptionWalk): raise ValueError(_("invalid suffix: {0} for option").format(val)) return values + def impl_validate_value(self, option, value, context): + pass + class DynOptionDescription(OptionDescription): def __init__(self, name, doc, children, requires=None, properties=None, @@ -561,9 +564,13 @@ class SynDynOptionDescription(object): class MasterSlaves(OptionDescription): __slots__ = ('master', 'slaves') - def __init__(self, name, doc, children, requires=None, properties=None): - #if master (same name has group) is set - #for collect all slaves + def __init__(self, + name, + doc, + children, + requires=None, + properties=None): + super(MasterSlaves, self).__init__(name, doc, children, @@ -572,10 +579,6 @@ class MasterSlaves(OptionDescription): self._group_type = groups.master slaves = [] master = children[0] - if master.impl_getname() != name: - raise ValueError(_('master group with wrong' - ' master name for {0}' - ).format(name)) for child in children[1:]: if child.impl_getdefault() != []: raise ValueError(_("not allowed default value for option {0} " @@ -604,8 +607,6 @@ class MasterSlaves(OptionDescription): raise ValueError(_("callback of master's option shall " "not refered a slave's ones")) #everything is ok, store references - #self.master = master - #self.slaves = tuple(slaves) for child in children: child._master_slaves = self master._add_dependency(self) @@ -644,41 +645,74 @@ class MasterSlaves(OptionDescription): c_opt = opt return c_opt in self._children[1] - def reset(self, opt, values, setting_properties, _commit=True, force_permissive=False): - for slave in self.getslaves(opt): - values.reset(slave, validate=False, _setting_properties=setting_properties, - _commit=_commit, force_permissive=force_permissive) + def reset(self, + opt, + values, + setting_properties, + _commit=True, + force_permissive=False): - def pop(self, opt, values, index): for slave in self.getslaves(opt): slave_path = slave.impl_getpath(values._getcontext()) - slavelen = values._p_.get_max_length(slave_path, None) - # just for raise if needed - if not values.is_default_owner(slave, validate_properties=False, - validate_meta=False, index=index): - multi = values._get_cached_value(slave, validate=False, - validate_properties=False, - ) - if isinstance(multi, Exception): - raise multi + values.reset(slave, + slave_path, + setting_properties, + validate=False, + _commit=_commit, + force_permissive=force_permissive) + + def pop(self, + opt, + path, + values, + index): + + for slave in self.getslaves(opt): + slave_path = slave.impl_getpath(values._getcontext()) + slavelen = values._p_.get_max_length(slave_path) + if not values.is_default_owner(slave, + validate_properties=False, + validate_meta=False, + index=index): + #FIXME # just for raise if needed + #multi = values.get_cached_value(slave, + # validate=False, + # validate_properties=False, + # ) + #if isinstance(multi, Exception): + # raise multi if slavelen > index: - values._p_.resetvalue_index(slave_path, index) + values._p_.resetvalue_index(slave_path, + index) if slavelen > index + 1: for idx in xrange(index + 1, slavelen): - values._p_.reduce_index(slave_path, idx) + values._p_.reduce_index(slave_path, + idx) - def getitem(self, values, opt, path, validate, force_permissive, - trusted_cached_properties, validate_properties, - slave_path=undefined, slave_value=undefined, - setting_properties=undefined, self_properties=undefined, index=None, + def getitem(self, + values, + opt, + path, + validate, + force_permissive, + trusted_cached_properties, + validate_properties, + setting_properties=undefined, + self_properties=undefined, + index=None, check_frozen=False): if self.is_master(opt): - return self._getmaster(values, opt, path, validate, + return self._getmaster(values, + opt, + path, + validate, force_permissive, - validate_properties, slave_path, - slave_value, self_properties, index, - setting_properties, check_frozen) + validate_properties, + self_properties, + index, + setting_properties, + check_frozen) else: return self._getslave(values, opt, path, validate, force_permissive, trusted_cached_properties, @@ -686,17 +720,26 @@ class MasterSlaves(OptionDescription): self_properties, index, check_frozen) - def _getmaster(self, values, opt, path, validate, force_permissive, - validate_properties, c_slave_path, - c_slave_value, self_properties, index, - setting_properties, check_frozen): - return values._get_cached_value(opt, path=path, validate=validate, - force_permissive=force_permissive, - validate_properties=validate_properties, - self_properties=self_properties, - from_masterslave=True, index=index, - setting_properties=setting_properties, - check_frozen=check_frozen) + def _getmaster(self, + values, + opt, + path, + validate, + force_permissive, + validate_properties, + self_properties, + index, + setting_properties, + check_frozen): + return values.get_cached_value(opt, + path=path, + validate=validate, + force_permissive=force_permissive, + validate_properties=validate_properties, + self_properties=self_properties, + index=index, + setting_properties=setting_properties, + check_frozen=check_frozen) def _getslave(self, values, opt, path, validate, force_permissive, trusted_cached_properties, validate_properties, setting_properties, @@ -725,20 +768,20 @@ class MasterSlaves(OptionDescription): master = self.getmaster(opt) context = values._getcontext() masterp = master.impl_getpath(context) - mastervalue = values._get_cached_value(master, path=masterp, validate=validate, - force_permissive=force_permissive, - validate_properties=validate_properties, - self_properties=self_properties, - from_masterslave=True, - setting_properties=setting_properties, - check_frozen=check_frozen) + mastervalue = values.get_cached_value(master, path=masterp, validate=validate, + force_permissive=force_permissive, + validate_properties=validate_properties, + self_properties=self_properties, + from_masterslave=True, + setting_properties=setting_properties, + check_frozen=check_frozen) if isinstance(mastervalue, Exception): if isinstance(mastervalue, PropertiesOptionError): mastervalue.set_orig_opt(opt) return mastervalue masterlen = len(mastervalue) - master_is_meta = values._is_meta(master, masterp, force_permissive=force_permissive) - multi = values._get_multi(opt, path) + #self._master_is_meta = values._is_meta(master, masterp, force_permissive=force_permissive) + multi = list() # values._get_multi(opt, path) if validate_properties: props = context.cfgimpl_get_settings().validate_properties(opt, False, check_frozen, @@ -748,68 +791,84 @@ class MasterSlaves(OptionDescription): setting_properties=setting_properties) if props: return props + #FIXME shouldn't have index!!! if index is None: indexes = xrange(0, masterlen) else: indexes = [index] for idx in indexes: - value = values._get_cached_value(opt, path, validate, - force_permissive, - trusted_cached_properties, - validate_properties, - with_meta=master_is_meta, - index=idx, - # not self_properties, - # depends to index - #self_properties=self_properties, - setting_properties=setting_properties, - masterlen=masterlen, - from_masterslave=True, - check_frozen=check_frozen) + value = values.get_cached_value(opt, path, validate, + force_permissive, + trusted_cached_properties, + validate_properties, + index=idx, + # not self_properties, + # depends to index + #self_properties=self_properties, + setting_properties=setting_properties, + from_masterslave=True, + check_frozen=check_frozen) if isinstance(value, Exception): if isinstance(value, PropertiesOptionError): err = value if index is None: - multi.append_properties_error(value) + multi.append(value) else: multi = value else: return value elif index is None: - multi.append(value, setitem=False, force=True, validate=False, - force_permissive=force_permissive) + multi.append(value) else: multi = value return multi - def validate(self, values, opt, index, path, setitem): + def validate(self, + values, + opt, + index, + path, + setitem): if self.is_master(opt): #for regen slave path base_path = '.'.join(path.split('.')[:-1]) + '.' for slave in self.getslaves(opt): slave_path = base_path + slave.impl_getname() slavelen = values._p_.get_max_length(slave_path) - self.validate_slave_length(index, slavelen, slave.impl_getname(), opt) + self.validate_slave_length(index, + slavelen, + slave.impl_getname(), + opt) else: - val_len = self.get_length(values, opt, slave_path=path) + val_len = self.get_length(values) if isinstance(val_len, Exception): return val_len - self.validate_slave_length(val_len, index, - opt.impl_getname(), opt, setitem=setitem) + self.validate_slave_length(val_len, + index, + opt.impl_getname(), + opt, + setitem=setitem) - def get_length(self, values, opt, validate=True, slave_path=undefined, - slave_value=undefined, force_permissive=False, master=None, - masterp=None, setting_properties=undefined): + def get_length(self, + values, + validate=True, + force_permissive=False, + master=None, + masterp=None, + setting_properties=undefined): """get master len with slave option""" if master is None: master = self.getmaster(None) if masterp is None: - masterp = master.impl_getpath(self._getcontext()) - if slave_value is undefined: - slave_path = undefined - value = self.getitem(values, master, masterp, validate, - force_permissive, None, True, slave_path=slave_path, - slave_value=slave_value, setting_properties=setting_properties) + masterp = master.impl_getpath(values._getcontext()) + value = self.getitem(values, + master, + masterp, + validate, + force_permissive, + None, + True, + setting_properties=setting_properties) if isinstance(value, Exception): return value return len(value) @@ -843,10 +902,9 @@ class MasterSlaves(OptionDescription): master = self.getmaster(opt) masterp = master.impl_getpath(context) - mastervalue = values._get_cached_value(master, path=masterp, - force_permissive=force_permissive, - from_masterslave=True, - setting_properties=setting_properties) + mastervalue = values.get_cached_value(master, path=masterp, + force_permissive=force_permissive, + setting_properties=setting_properties) if isinstance(mastervalue, Exception): return mastervalue masterlen = len(mastervalue) @@ -857,9 +915,15 @@ class MasterSlaves(OptionDescription): else: for slave in self.getslaves(master): slave_path = slave.impl_getpath(context) - slavelen = values._p_.get_max_length(slave_path, None) + slavelen = values._p_.get_max_length(slave_path) self.validate_slave_length(masterlen, slavelen, slave.impl_getname(), master) + def impl_validate_value(self, option, value, context): + if option.impl_is_master_slaves('master') and isinstance(value, list): + if len(value) < context._impl_length: + return ValueError(_('cannot reduce length of master "{}"' + '').format(option.impl_get_display_name())) + def _impl_getpaths(klass, include_groups, _currpath): """returns a list of all paths in klass, recursively diff --git a/tiramisu/setting.py b/tiramisu/setting.py index fdab002..2887ae2 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -353,15 +353,25 @@ class Settings(object): path = opt.impl_getpath(self._getcontext()) return self.getproperties(opt, path) - def getproperties(self, opt, path, setting_properties=undefined, index=None, obj=True): + def getproperties(self, + opt, + path, + setting_properties=undefined, + index=None, + obj=True): """get properties for a specified option """ - properties = self._getproperties(opt, path, index=index, + properties = self._getproperties(opt, + path, + index=index, setting_properties=setting_properties) if obj: return Property(self, properties, opt, path) return properties + def getcontextproperties(self): + return self._getproperties() + def __setitem__(self, opt, value): # pragma: optional cover raise ValueError(_('you should only append/remove properties')) @@ -377,9 +387,13 @@ class Settings(object): self._p_.delproperties(_path) self._getcontext().cfgimpl_reset_cache(opt=opt, path=_path, only=('settings', 'values')) - def _getproperties(self, opt=None, path=None, - setting_properties=undefined, read_write=True, - apply_requires=True, index=None): + def _getproperties(self, + opt=None, + path=None, + setting_properties=undefined, + read_write=True, + apply_requires=True, + index=None): """ """ if opt is None: diff --git a/tiramisu/storage/dictionary/value.py b/tiramisu/storage/dictionary/value.py index 336a34e..92df7ce 100644 --- a/tiramisu/storage/dictionary/value.py +++ b/tiramisu/storage/dictionary/value.py @@ -67,7 +67,7 @@ class Values(Cache): return vidx # value - def setvalue(self, path, value, owner, index, session, commit): + def setvalue(self, path, value, owner, index, commit): """set value for a path a specified value must be associated to an owner """ @@ -137,7 +137,7 @@ class Values(Cache): _resetvalue_index(3) self._values = tuple(values) - def resetvalue(self, path, session, commit): + def resetvalue(self, path, commit): """remove value means delete value in storage """ def _resetvalue(nb): @@ -174,7 +174,7 @@ class Values(Cache): return values # owner - def setowner(self, path, owner, session, index=None): + def setowner(self, path, owner, index=None): """change owner for a path """ idx = self._values[0].index(path) @@ -188,14 +188,14 @@ class Values(Cache): lst[3] = tuple(values[0]) self._values = tuple(lst) - def get_max_length(self, path, session): + def get_max_length(self, path): if path in self._values[0]: idx = self._values[0].index(path) else: return 0 return max(self._values[1][idx]) + 1 - def getowner(self, path, default, session, index=None, only_default=False, + def getowner(self, path, default, index=None, only_default=False, with_value=False): """get owner for a path return: owner object @@ -271,11 +271,11 @@ class Values(Cache): if raises: raise ValueError(_("information's item not found {0}").format(key)) - def exportation(self, session, fake=False): + def exportation(self, fake=False): return self._values def importation(self, export): self._values = export -def delete_session(session_id, session): +def delete_session(session_id): raise ValueError(_('a dictionary cannot be persistent')) diff --git a/tiramisu/storage/util.py b/tiramisu/storage/util.py index 59a941c..5cf1fc7 100644 --- a/tiramisu/storage/util.py +++ b/tiramisu/storage/util.py @@ -15,6 +15,12 @@ # You should have received a copy of the GNU Lesser General Public License # along with this program. If not, see . # ____________________________________________________________ +FIXME = 0 +def POUET(obj): + return(obj.__class__.__name__.lower()) + +DEBUG = False +#DEBUG = True class Cache(object): @@ -29,17 +35,41 @@ class Cache(object): """add val in cache for a specified path if slave, add index """ + if DEBUG: + global FIXME + FIXME += 1 + print('ca set cache', path, val, POUET(self), FIXME) + #if path is not None and (path.startswith('od.st.') or path.startswith('od.dod.')): + # raise Exception('mais ... mais ... mais') + #if FIXME == 111: + # raise Exception('rah') self._cache.setdefault(path, {})[index] = (val, time) def getcache(self, path, exp, index): value, created = self._cache[path][index] if created is None or exp <= created: + if DEBUG: + global FIXME + FIXME += 1 + print('ca trouve dans le cache', path, value, POUET(self), FIXME) + #if path is not None and (path.startswith('od.st.') or path.startswith('od.dod.')): + # raise Exception('mais ... mais ... mais') + #if FIXME == 45: + # raise Exception('rah') return True, value return False, None # pragma: no cover def delcache(self, path): """remove cache for a specified path """ + if DEBUG: + global FIXME + FIXME += 1 + print('ca del cache', path, POUET(self), FIXME) + #if path is not None and (path.startswith('od.st.') or path.startswith('od.dod.')): + # raise Exception('mais ... mais ... mais') + #if FIXME == 23: + # raise Exception('rah') if path in self._cache: del self._cache[path] @@ -48,6 +78,8 @@ class Cache(object): :param path: the path's option """ + if DEBUG: + print('ca cherche dans le cache', path, POUET(self)) return path in self._cache and index in self._cache[path] def reset_expired_cache(self, exp): @@ -63,6 +95,8 @@ class Cache(object): def reset_all_cache(self): "empty the cache" + if DEBUG: + print('bzzzzzzzzzzzz delete tout le cache', POUET(self)) self._cache.clear() def get_cached(self): diff --git a/tiramisu/value.py b/tiramisu/value.py index efdbed9..5b4d807 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -54,76 +54,129 @@ class Values(object): raise ConfigError(_('the context does not exist anymore')) return context - def _get_multi(self, opt, path): - return Multi([], self.context, opt, path) + def getdefaultvalue(self, + opt, + path, + index=None): + """get default value: + - get meta config value or + - get calculated value or + - get default value + :param opt: the `option.Option()` object + :param path: path for `option.Option()` object + :type path: str + :param index: index of a multi/submulti + :type index: int + :returns: default value + """ + return self._getdefaultvalue(opt, + path, + index, + True, + self._getcontext()) - def _getdefaultvalue(self, opt, path, with_meta, index, submulti_index, validate, - _orig_context=undefined): - if _orig_context is undefined: - _orig_context = self._getcontext() + def _getdefaultvalue(self, + opt, + path, + index, + validate, + _orig_context): + def _reset_cache(): + # calculated value could be a new value, so reset cache + _orig_context.cfgimpl_reset_cache(opt=opt, + path=path, + only=('values', 'properties')) + + #FIXME with_meta should be calculated here... + with_meta = True if with_meta: meta = self._getcontext().cfgimpl_get_meta() if meta is not None: - value = meta.cfgimpl_get_values( - )._get_cached_value(opt, path, index=index, submulti_index=submulti_index, - from_masterslave=True, _orig_context=_orig_context) + # retrieved value from meta config + value = meta.cfgimpl_get_values().get_cached_value(opt, + path, + index=index, + _orig_context=_orig_context) if isinstance(value, Exception): + # if properties error, return an other default value if not isinstance(value, PropertiesOptionError): # pragma: no cover + # unexpected error, should not happened raise value else: - if isinstance(value, Multi): - new_value = [] - for val in value: - if isinstance(val, SubMulti): - val = list(val) - new_value.append(val) - value = new_value - del new_value return value - # if value has callback and is not set + if opt.impl_has_callback(): + # if value has callback, calculate value callback, callback_params = opt.impl_get_callback() - value = carry_out_calculation(opt, context=_orig_context, + value = carry_out_calculation(opt, + context=_orig_context, callback=callback, callback_params=callback_params, - index=index, validate=validate) - _orig_context.cfgimpl_reset_cache(opt=opt, path=path, only=('values', 'properties')) + index=index, + validate=validate) if isinstance(value, list) and index is not None: - #if return a list and index is set, return value only if - #it's a submulti without submulti_index and without list of list - if opt.impl_is_submulti() and submulti_index is undefined and \ - (len(value) == 0 or not isinstance(value[0], list)): + # if value is a list and index is set + if opt.impl_is_submulti() and (value == [] or not isinstance(value[0], list)): + # return value only if it's a submulti and not a list of list + _reset_cache() return value - if not opt.impl_is_submulti() and len(value) > index: + + if len(value) > index: + # return the value for specified index if found + _reset_cache() return value[index] - else: + # there is no calculate value for this index, + # so return an other default value + elif isinstance(value, list): + # value is a list, but no index specified + _reset_cache() + if opt.impl_is_submulti() and (value == [] or not isinstance(value[0], list)): + # if submulti, return a list of value + return [value] + # otherwise just return the value return value - # now try to get default value + elif index is not None: + # if not list but with index + _reset_cache() + if opt.impl_is_submulti(): + # if submulti, return a list of value + return [value] + # otherwise just return the value + return value + else: + _reset_cache() + # not a list or index is None + if opt.impl_is_submulti(): + # return a list of list for a submulti + return [[value]] + elif opt.impl_is_multi(): + # return a list for a multi + return [value] + # not a list, return value + return value + + # now try to get default value: + # - if opt is a submulti, return a list a list + # - if opt is a multi, return a list + # - default value value = opt.impl_getdefault() if opt.impl_is_multi() and index is not None: - if value == []: - value = opt.impl_getdefault_multi() - if submulti_index is undefined and opt.impl_is_submulti(): - if value is None: - value = [] - elif not isinstance(value, list): - value = [value] + # if index, must return good value for this index + if len(value) > index: + value = value[index] else: - if len(value) > index: - value = value[index] - else: - value = opt.impl_getdefault_multi() - if submulti_index is undefined and opt.impl_is_submulti(): - if value is None: - value = [] - elif not isinstance(value, list): - value = [value] - if opt.impl_is_submulti() and not isinstance(value, list) and submulti_index is undefined: - value = [value] + # no value for this index, retrieve default multi value + # default_multi is already a list for submulti + value = opt.impl_getdefault_multi() return value - def _getvalue(self, opt, path, self_properties, index, submulti_index, - with_meta, masterlen, session, validate, _orig_context): + def _getvalue(self, + opt, + path, + self_properties, + index, + validate, + _orig_context): """actually retrieves the value :param opt: the `option.Option()` object @@ -136,8 +189,11 @@ class Values(object): _index = None else: _index = index - owner, value = self._p_.getowner(path, owners.default, session, only_default=True, - index=_index, with_value=True) + owner, value = self._p_.getowner(path, + owners.default, + only_default=True, + index=_index, + with_value=True) is_default = owner == owners.default if not is_default and not force_default: if index is not None and not opt.impl_is_master_slaves('slave'): @@ -147,8 +203,11 @@ class Values(object): #so return default value else: return value - return self._getdefaultvalue(opt, path, with_meta, index, - submulti_index, validate, _orig_context) + return self._getdefaultvalue(opt, + path, + index, + validate, + _orig_context) def get_modified_values(self): return self._p_.get_modified_values() @@ -163,55 +222,129 @@ class Values(object): path = opt.impl_getpath(self._getcontext()) return self._contains(path) - def _contains(self, path, session=None): - if session is None: - session = self._p_.getsession() - return self._p_.hasvalue(path, session) + def _contains(self, path): + return self._p_.hasvalue(path) - def __delitem__(self, opt): - """overrides the builtins `del()` instructions""" - self.reset(opt) - - def reset(self, opt, path=None, validate=True, _setting_properties=None, _commit=True, + def reset(self, + opt, + path, + setting_properties, + validate=True, + _commit=True, force_permissive=False): + context = self._getcontext() setting = context.cfgimpl_get_settings() - if path is None: - path = opt.impl_getpath(context) - if _setting_properties is None: - _setting_properties = setting._getproperties(read_write=False) - session = self._p_.getsession() - hasvalue = self._contains(path, session) + hasvalue = self._contains(path) - if validate and hasvalue and 'validator' in _setting_properties: - session = context.cfgimpl_get_values()._p_.getsession() - fake_context = context._gen_fake_values(session) + if validate and hasvalue and 'validator' in setting_properties: + fake_context = context._gen_fake_values() fake_value = fake_context.cfgimpl_get_values() - fake_value.reset(opt, path, validate=False) - ret = fake_value._get_cached_value(opt, path, - setting_properties=_setting_properties, - check_frozen=True, - force_permissive=force_permissive) + fake_value.reset(opt, + path, + setting_properties, + validate=False) + ret = fake_value.get_cached_value(opt, + path, + setting_properties=setting_properties, + check_frozen=True, + force_permissive=force_permissive) if isinstance(ret, Exception): raise ret if opt.impl_is_master_slaves('master'): - opt.impl_get_master_slaves().reset(opt, self, _setting_properties, _commit=_commit, + opt.impl_get_master_slaves().reset(opt, + self, + setting_properties, + _commit=_commit, force_permissive=force_permissive) if hasvalue: if 'force_store_value' in setting._getproperties(opt=opt, path=path, - setting_properties=_setting_properties, + setting_properties=setting_properties, read_write=False, apply_requires=False): - value = self._getdefaultvalue(opt, path, True, undefined, undefined, validate) + value = self._getdefaultvalue(opt, + path, + True, + undefined, + validate, + context) if isinstance(value, Exception): # pragma: no cover raise value - self._setvalue(opt, path, value, force_owner=owners.forced, commit=_commit) + self._setvalue(opt, + path, + value, + owners.forced, + None, + commit=_commit) else: - self._p_.resetvalue(path, session, _commit) - context.cfgimpl_reset_cache(opt=opt, path=path, only=('values', 'properties')) + self._p_.resetvalue(path, + _commit) + context.cfgimpl_reset_cache(opt=opt, + path=path, + only=('values', 'properties')) - def _isempty(self, opt, value, force_allow_empty_list=False, index=None): + def reset_slave(self, + opt, + path, + index, + setting_properties, + validate=True, + force_permissive=False): + + context = self._getcontext() + if validate and 'validator' in setting_properties: + fake_context = context._gen_fake_values() + fake_value = fake_context.cfgimpl_get_values() + fake_value.reset_slave(opt, + path, + index, + setting_properties, + validate=False) + ret = fake_value.get_cached_value(opt, + path, + index=index, + setting_properties=setting_properties, + check_frozen=True, + force_permissive=force_permissive) + if isinstance(ret, Exception): + raise ret + self._p_.resetvalue_index(path, index) + + def reset_master(self, + subconfig, + opt, + path, + index, + force_permissive, + setting_properties): + + current_value = self.get_cached_value(opt, + path, + setting_properties=setting_properties, + check_frozen=True, + force_permissive=force_permissive) + current_value.pop(index) + ret = self.setitem(opt, + current_value, + path, + force_permissive=force_permissive, + not_raises=True, + index=None, + setting_properties=setting_properties, + _commit=True) + if ret: + return ret + subconfig.cfgimpl_get_description().pop(opt, + path, + self, + index) + + def _isempty(self, + opt, + value, + force_allow_empty_list=False, + index=None): "convenience method to know if an option is empty" if value is undefined: return False @@ -235,15 +368,21 @@ class Values(object): def __getitem__(self, opt): "enables us to use the pythonic dictionary-like access to values" - return self._get_cached_value(opt) + return self.get_cached_value(opt) - def _get_cached_value(self, opt, path=None, validate=True, - force_permissive=False, trusted_cached_properties=True, - validate_properties=True, - setting_properties=undefined, self_properties=undefined, - index=None, submulti_index=undefined, from_masterslave=False, - with_meta=True, masterlen=undefined, check_frozen=False, - session=None, display_warnings=True, _orig_context=undefined): + def get_cached_value(self, + opt, + path=None, + validate=True, + force_permissive=False, + trusted_cached_properties=True, + validate_properties=True, + setting_properties=undefined, + self_properties=undefined, + index=None, + check_frozen=False, + display_warnings=True, + _orig_context=undefined): context = self._getcontext() settings = context.cfgimpl_get_settings() if path is None: @@ -252,7 +391,8 @@ class Values(object): if setting_properties is undefined: setting_properties = settings._getproperties(read_write=False) if self_properties is undefined: - self_properties = settings._getproperties(opt, path, + self_properties = settings._getproperties(opt, + path, read_write=False, setting_properties=setting_properties, index=index) @@ -264,11 +404,14 @@ class Values(object): if index: value = value[index] if is_cached: - if opt.impl_is_multi() and not isinstance(value, Multi) and index is None: - value = Multi(value, self.context, opt, path) + #if opt.impl_is_multi() and not isinstance(value, Multi) and index is None: + # value = Multi(value, self.context, opt, path) if not trusted_cached_properties: # revalidate properties (because of not default properties) - props = settings.validate_properties(opt, False, False, value=value, + props = settings.validate_properties(opt, + False, + False, + value=value, path=path, force_permissive=force_permissive, setting_properties=setting_properties, @@ -277,38 +420,35 @@ class Values(object): if props: return props return value - if session is None: - session = self._p_.getsession() - if not from_masterslave and opt.impl_is_master_slaves(): - val = opt.impl_get_master_slaves().getitem(self, opt, path, - validate, - force_permissive, - trusted_cached_properties, - validate_properties, - session, - setting_properties=setting_properties, - index=index, - self_properties=self_properties, - check_frozen=check_frozen) + #if not from_masterslave and opt.impl_is_master_slaves(): + # val = opt.impl_get_master_slaves().getitem(self, opt, path, + # validate, + # force_permissive, + # trusted_cached_properties, + # validate_properties, + # setting_properties=setting_properties, + # index=index, + # self_properties=self_properties, + # check_frozen=check_frozen) + #else: + if _orig_context is not undefined: + _context = _orig_context else: - val = self._get_validated_value(opt, path, validate, - force_permissive, - validate_properties, - setting_properties, - self_properties, - with_meta=with_meta, - masterlen=masterlen, - index=index, - submulti_index=submulti_index, - check_frozen=check_frozen, - session=session, - display_warnings=display_warnings, - _orig_context=_orig_context) + _context = context + val = self._get_validated_value(opt, + path, + validate, + force_permissive, + validate_properties, + setting_properties, + self_properties, + index=index, + check_frozen=check_frozen, + display_warnings=display_warnings, + _orig_context=_context) if isinstance(val, Exception): return val - # cache doesn't work with SubMulti yet - if not from_masterslave and index is None and not isinstance(val, SubMulti) and \ - 'cache' in setting_properties and \ + if index is None and 'cache' in setting_properties and \ validate and validate_properties and force_permissive is False \ and trusted_cached_properties is True and _orig_context is undefined: if 'expire' in setting_properties: @@ -318,14 +458,17 @@ class Values(object): self._p_.setcache(path, val, ntime, None) return val - def _get_validated_value(self, opt, path, validate, force_permissive, - validate_properties, setting_properties, + def _get_validated_value(self, + opt, + path, + validate, + force_permissive, + validate_properties, + setting_properties, self_properties, - index=None, submulti_index=undefined, - with_meta=True, - masterlen=undefined, + index=None, check_frozen=False, - session=None, display_warnings=True, + display_warnings=True, _orig_context=undefined): """same has getitem but don't touch the cache index is None for slave value, if value returned is not a list, just return [] @@ -333,10 +476,12 @@ class Values(object): context = self._getcontext() setting = context.cfgimpl_get_settings() config_error = None - if session is None: - session = self._p_.getsession() - value = self._getvalue(opt, path, self_properties, index, submulti_index, - with_meta, masterlen, session, validate, _orig_context) + value = self._getvalue(opt, + path, + self_properties, + index, + validate, + _orig_context) if isinstance(value, Exception): value_error = True if isinstance(value, ConfigError): @@ -355,22 +500,11 @@ class Values(object): raise value else: value_error = False - if opt.impl_is_multi(): - if index is None: - value = Multi(value, self.context, opt, path) - elif opt.impl_is_submulti() and submulti_index is undefined: - value = SubMulti(value, self.context, opt, path, - index) - if validate: - if submulti_index is undefined: - force_submulti_index = None - else: - force_submulti_index = submulti_index - err = opt.impl_validate(value, context, + err = opt.impl_validate(value, + context, 'validator' in setting_properties, force_index=index, - force_submulti_index=force_submulti_index, display_error=True, display_warnings=False, setting_properties=setting_properties) @@ -385,7 +519,10 @@ class Values(object): val_props = undefined else: val_props = value - props = setting.validate_properties(opt, False, check_frozen, value=val_props, + props = setting.validate_properties(opt, + False, + check_frozen, + value=val_props, path=path, force_permissive=force_permissive, setting_properties=setting_properties, @@ -394,10 +531,10 @@ class Values(object): if props: return props if not value_error and validate and display_warnings: - opt.impl_validate(value, context, + opt.impl_validate(value, + context, 'validator' in setting_properties, force_index=index, - force_submulti_index=force_submulti_index, display_error=False, display_warnings=display_warnings, setting_properties=setting_properties) @@ -405,122 +542,116 @@ class Values(object): return config_error return value - def __setitem__(self, opt, value): - raise ConfigError(_('you should only set value with config')) + def setitem(self, + opt, + value, + path, + force_permissive, + not_raises, + index, + setting_properties, + _commit): - def setitem(self, opt, value, path, force_permissive=False, - check_frozen=True, not_raises=False, index=None, - _setting_properties=undefined, _commit=True): - # check_frozen is, for example, used with "force_store_value" - # user didn't change value, so not write - # valid opt context = self._getcontext() - if 'validator' in _setting_properties: - session = context.cfgimpl_get_values()._p_.getsession() + owner = context.cfgimpl_get_settings().getowner() + if 'validator' in setting_properties: if opt._has_consistencies(): - fake_context = context._gen_fake_values(session) - fake_values = fake_context.cfgimpl_get_values() - fake_values._setvalue(opt, path, value, index=index) + # set value to a fake config when option has dependency + # validation will be complet in this case (consistency, ...) + tested_context = context._gen_fake_values() + tested_values = tested_context.cfgimpl_get_values() + tested_values._setvalue(opt, + path, + value, + index=index, + owner=owner) else: - fake_context = context - fake_values = self - props = fake_values.validate(opt, value, path, - check_frozen=check_frozen, - force_permissive=force_permissive, - setting_properties=_setting_properties, - session=session, not_raises=not_raises, - index=index, setitem=True) - if props and not_raises: + tested_context = context + tested_values = self + props = tested_values.validate_setitem(opt, + value, + path, + force_permissive, + setting_properties, + index) + if props: + if not not_raises: + raise props return props - err = opt.impl_validate(value, fake_context, display_warnings=False, force_index=index, - setting_properties=_setting_properties) - if err: - if not_raises: - return err - raise err - opt.impl_validate(value, fake_context, display_error=False, - setting_properties=_setting_properties) - self._setvalue(opt, path, value, index=index, commit=_commit) - def _setvalue(self, opt, path, value, force_owner=undefined, index=None, commit=True): + self._setvalue(opt, + path, + value, + owner, + index=index, + commit=_commit) + + def validate_setitem(self, + opt, + value, + path, + force_permissive, + setting_properties, + index): + context = self._getcontext() - context.cfgimpl_reset_cache(opt=opt, path=path, only=('values', 'properties')) - if force_owner is undefined: - owner = context.cfgimpl_get_settings().getowner() - else: - owner = force_owner - # in storage, value must not be a multi - if isinstance(value, Multi): - if not opt.impl_is_master_slaves('slave') or index is None: - value = list(value) - if opt.impl_is_submulti(): - for idx, val in enumerate(value): - if isinstance(val, SubMulti): - value[idx] = list(val) - else: - value = value[index] - session = self._p_.getsession() - #FIXME pourquoi là et pas dans masterslaves ?? - if opt.impl_is_master_slaves('slave'): - if index is not None: - self._p_.setvalue(path, value, owner, index, session, commit) - else: - self._p_.resetvalue(path, session, commit) - for idx, val in enumerate(value): - self._p_.setvalue(path, val, owner, idx, session, commit) - else: - self._p_.setvalue(path, value, owner, None, session, commit) - del(session) - - def validate(self, opt, value, path, check_frozen=True, force_permissive=False, - setting_properties=undefined, valid_masterslave=True, - not_raises=False, session=None, index=None, setitem=False): - if valid_masterslave and opt.impl_is_master_slaves(): - if session is None: - session = self._p_.getsession() - setitem = True - if opt.impl_is_master_slaves('master'): - masterlen = len(value) - slavelen = None - elif index is not None: - masterlen = None - slavelen = index - setitem = False - else: - masterlen = None - slavelen = len(value) - opt.impl_get_master_slaves().impl_validate(self._getcontext(), force_permissive, - setting_properties, masterlen=masterlen, - slavelen=slavelen, opt=opt, setitem=setitem) - #val = opt.impl_get_master_slaves().impl_validate(self, opt, len_value, path, session, setitem=setitem) - #if isinstance(val, Exception): - # return val - props = self._getcontext().cfgimpl_get_settings().validate_properties(opt, - False, - check_frozen, - value=value, - path=path, - force_permissive=force_permissive, - setting_properties=setting_properties, - index=index) + # First validate properties with this value + props = context.cfgimpl_get_settings().validate_properties(opt, + False, + True, + value=value, + path=path, + force_permissive=force_permissive, + setting_properties=setting_properties, + index=index) if props: - if not_raises: - return props - raise props + return props + # Value must be valid for option + err = opt.impl_validate(value, + context, + display_warnings=False, + force_index=index, + setting_properties=setting_properties) + if err: + return err + # No error found so emit warnings + opt.impl_validate(value, + context, + display_error=False, + force_index=index, + setting_properties=setting_properties) - def _is_meta(self, opt, path, session=None, force_permissive=False): + def _setvalue(self, + opt, + path, + value, + owner, + index=None, + commit=True): + + self._getcontext().cfgimpl_reset_cache(opt=opt, + path=path, + only=('values', 'properties')) + if isinstance(value, list): + # copy + value = list(value) + self._p_.setvalue(path, + value, + owner, + index, + commit) + + def _is_meta(self, opt, path, force_permissive=False): context = self._getcontext() if context.cfgimpl_get_meta() is None: return False setting = context.cfgimpl_get_settings() self_properties = setting._getproperties(opt, path, read_write=False) - if session is None: - session = self._p_.getsession() return self.is_default_owner(opt, path=path, validate_properties=True, validate_meta=False, index=None, force_permissive=force_permissive) - def getowner(self, opt, index=None, force_permissive=False, session=None): + def getowner(self, opt, index=None, force_permissive=False): """ retrieves the option's owner @@ -533,16 +664,22 @@ class Values(object): not isinstance(opt, DynSymLinkOption): opt = opt._impl_getopt() path = opt.impl_getpath(self._getcontext()) - return self._getowner(opt, path, session, index=index, force_permissive=force_permissive) + return self._getowner(opt, + path, + index=index, + force_permissive=force_permissive) - def _getowner(self, opt, path, session, validate_properties=True, - force_permissive=False, validate_meta=undefined, - self_properties=undefined, only_default=False, + def _getowner(self, + opt, + path, + validate_properties=True, + force_permissive=False, + validate_meta=undefined, + self_properties=undefined, + only_default=False, index=None): """get owner of an option """ - if session is None: - session = self._p_.getsession() if not isinstance(opt, Option) and not isinstance(opt, DynSymLinkOption): raise ConfigError(_('owner only avalaible for an option')) @@ -553,28 +690,32 @@ class Values(object): if 'frozen' in self_properties and 'force_default_on_freeze' in self_properties: return owners.default if validate_properties: - value = self._get_cached_value(opt, path=path, force_permissive=force_permissive, - self_properties=self_properties, session=session, - index=index) + value = self.get_cached_value(opt, + path=path, + force_permissive=force_permissive, + self_properties=self_properties, + index=index) if isinstance(value, Exception): raise value - owner = self._p_.getowner(path, owners.default, session, only_default=only_default, index=index) + owner = self._p_.getowner(path, owners.default, only_default=only_default, index=index) if validate_meta is undefined: if opt.impl_is_master_slaves('slave'): master = opt.impl_get_master_slaves().getmaster(opt) masterp = master.impl_getpath(context) - validate_meta = self._is_meta(master, masterp, session) + validate_meta = self._is_meta(master, masterp) else: validate_meta = True if validate_meta and owner is owners.default: meta = context.cfgimpl_get_meta() if meta is not None: - owner = meta.cfgimpl_get_values()._getowner(opt, path, session, + owner = meta.cfgimpl_get_values()._getowner(opt, + path, validate_properties=validate_properties, force_permissive=force_permissive, self_properties=self_properties, - only_default=only_default, index=index) + only_default=only_default, + index=index) return owner def setowner(self, opt, owner, index=None, force_permissive=False): @@ -588,7 +729,6 @@ class Values(object): raise TypeError(_("invalid generic owner {0}").format(str(owner))) path = opt.impl_getpath(self._getcontext()) - session = self._p_.getsession() props = self._getcontext().cfgimpl_get_settings().validate_properties(opt, False, True, @@ -597,10 +737,10 @@ class Values(object): force_permissive=force_permissive) if props: raise props - if not self._p_.hasvalue(path, session): + if not self._p_.hasvalue(path): raise ConfigError(_('no value for {0} cannot change owner to {1}' '').format(path, owner)) - self._p_.setowner(path, owner, session, index=index) + self._p_.setowner(path, owner, index=index) def is_default_owner(self, opt, path=None, validate_properties=True, validate_meta=True, index=None, @@ -612,19 +752,30 @@ class Values(object): """ if path is None: path = opt.impl_getpath(self._getcontext()) - return self._is_default_owner(opt, path, session=None, + return self._is_default_owner(opt, + path, validate_properties=validate_properties, - validate_meta=validate_meta, index=index, + validate_meta=validate_meta, + index=index, force_permissive=force_permissive) - def _is_default_owner(self, opt, path, session, validate_properties=True, - validate_meta=True, self_properties=undefined, - index=None, force_permissive=False): - d = self._getowner(opt, path, session, validate_properties=validate_properties, - validate_meta=validate_meta, - self_properties=self_properties, only_default=True, - index=index, force_permissive=force_permissive) - return d == owners.default + def _is_default_owner(self, + opt, + path, + validate_properties=True, + validate_meta=True, + self_properties=undefined, + index=None, + force_permissive=False): + owner = self._getowner(opt, + path, + validate_properties=validate_properties, + validate_meta=validate_meta, + self_properties=self_properties, + only_default=True, + index=index, + force_permissive=force_permissive) + return owner == owners.default # information def set_information(self, key, value): @@ -688,13 +839,13 @@ class Values(object): read_write=False, setting_properties=setting_properties) if 'mandatory' in self_properties or 'empty' in self_properties: - err = self._get_cached_value(opt, path=path, - trusted_cached_properties=False, - force_permissive=True, - setting_properties=setting_properties, - self_properties=self_properties, - validate=True, - display_warnings=False) + err = self.get_cached_value(opt, path=path, + trusted_cached_properties=False, + force_permissive=True, + setting_properties=setting_properties, + self_properties=self_properties, + validate=True, + display_warnings=False) if opt.impl_is_master_slaves('slave') and isinstance(err, list): for val in err: ret = _is_properties_option(val, path) @@ -723,277 +874,3 @@ class Values(object): err = context.getattr(path, returns_raise=True) if isinstance(err, Exception) and not isinstance(err, PropertiesOptionError): # pragma: no cover raise err - - -# ____________________________________________________________ -# multi types -class Multi(list): - """multi options values container - that support item notation for the values of multi options""" - __slots__ = ('opt', 'path', 'context', '__weakref__') - - def __init__(self, value, context, opt, path): - """ - :param value: the Multi wraps a list value - :param context: the home config that has the values - :param opt: the option object that have this Multi value - :param path: path of the option - """ - if value is None: - value = [] - if not opt.impl_is_submulti() and isinstance(value, Multi): - raise ValueError(_('{0} is already a Multi ').format( - opt.impl_getname())) - self.opt = opt - self.path = path - if not isinstance(context, weakref.ReferenceType): - raise ValueError('context must be a Weakref') - self.context = context - if not isinstance(value, list): - if not '_index' in self.__slots__ and opt.impl_is_submulti(): - value = [[value]] - else: - value = [value] - elif value != [] and not '_index' in self.__slots__ and \ - opt.impl_is_submulti() and not isinstance(value[0], list): - value = [value] - super(Multi, self).__init__(value) - if opt.impl_is_submulti(): - if not '_index' in self.__slots__: - for idx, val in enumerate(self): - if not isinstance(val, SubMulti): - super(Multi, self).__setitem__(idx, SubMulti(val, - context, - opt, path, - idx)) - self[idx].refmulti = weakref.ref(self) - - def _getcontext(self): - """context could be None, we need to test it - context is None only if all reference to `Config` object is deleted - (for example we delete a `Config` and we manipulate a reference to - old `SubConfig`, `Values`, `Multi` or `Settings`) - """ - context = self.context() - if context is None: - raise ConfigError(_('the context does not exist anymore')) - return context - - def __setitem__(self, index, value): - self._setitem(index, value) - - def _setitem(self, index, value, validate=True): - context = self._getcontext() - setting = context.cfgimpl_get_settings() - setting_properties = setting._getproperties(read_write=False) - if index < 0: - index = self.__len__() + index - if 'validator' in setting_properties and validate: - session = context.cfgimpl_get_values()._p_.getsession() - fake_context = context._gen_fake_values(session) - fake_multi = Multi(list(self), weakref.ref(fake_context), self.opt, self.path) - fake_multi._setitem(index, value, validate=False) - self._validate(value, fake_context, index, True) - #assume not checking mandatory property - super(Multi, self).__setitem__(index, value) - self._store(index=index) - - #def __repr__(self, *args, **kwargs): - # return super(Multi, self).__repr__(*args, **kwargs) - - def __getitem__(self, index): - value = super(Multi, self).__getitem__(index) - if isinstance(value, PropertiesOptionError): - raise value - return value - - def __delitem__(self, index): - return self.pop(index) - - def _getdefaultvalue(self, index): - values = self._getcontext().cfgimpl_get_values() - value = values._getdefaultvalue(self.opt, self.path, True, index, - undefined, True) - if self.opt.impl_is_submulti(): - value = SubMulti(value, self.context, self.opt, self.path, index) - return value - - def append(self, value=undefined, force=False, setitem=True, validate=True, - force_permissive=False): - """the list value can be updated (appened) - only if the option is a master - """ - if not force and self.opt.impl_is_master_slaves('slave'): - raise SlaveError(_("cannot append a value on a multi option {0}" - " which is a slave").format(self.opt.impl_getname())) - index = self.__len__() - if value is undefined: - value = self._getdefaultvalue(index) - if validate and value not in [None, undefined]: - context = self._getcontext() - setting = context.cfgimpl_get_settings() - setting_properties = setting._getproperties(read_write=False) - if 'validator' in setting_properties: - session = context.cfgimpl_get_values()._p_.getsession() - fake_context = context._gen_fake_values(session) - fake_multi = Multi(list(self), weakref.ref(fake_context), self.opt, self.path) - fake_multi.append(value, validate=False, force=True, - setitem=setitem) - self._validate(value, fake_context, index, True) - if not '_index' in self.__slots__ and self.opt.impl_is_submulti(): - if not isinstance(value, SubMulti): - value = SubMulti(value, self.context, self.opt, self.path, index) - value.refmulti = weakref.ref(self) - super(Multi, self).append(value) - if setitem: - self._store(force=force) - - def append_properties_error(self, err): - super(Multi, self).append(err) - - def sort(self, cmp=None, key=None, reverse=False): - if self.opt.impl_is_master_slaves(): - raise SlaveError(_("cannot sort multi option {0} if master or slave" - "").format(self.opt.impl_getname())) - if sys.version_info[0] >= 3: # pragma: no cover - if cmp is not None: - raise ValueError(_('cmp is not permitted in python v3 or ' - 'greater')) - super(Multi, self).sort(key=key, reverse=reverse) - else: - super(Multi, self).sort(cmp=cmp, key=key, reverse=reverse) - self._store() - - def reverse(self): - if self.opt.impl_is_master_slaves(): - raise SlaveError(_("cannot reverse multi option {0} if master or " - "slave").format(self.opt.impl_getname())) - super(Multi, self).reverse() - self._store() - - def insert(self, index, value, validate=True): - if self.opt.impl_is_master_slaves(): - raise SlaveError(_("cannot insert multi option {0} if master or " - "slave").format(self.opt.impl_getname())) - context = self._getcontext() - setting = setting = context.cfgimpl_get_settings() - setting_properties = setting._getproperties(read_write=False) - if 'validator' in setting_properties and validate and value is not None: - session = context.cfgimpl_get_values()._p_.getsession() - fake_context = context._gen_fake_values(session) - fake_multi = Multi(list(self), weakref.ref(fake_context), self.opt, self.path) - fake_multi.insert(index, value, validate=False) - self._validate(value, fake_context, index, True) - super(Multi, self).insert(index, value) - self._store() - - def extend(self, iterable, validate=True): - if self.opt.impl_is_master_slaves(): - raise SlaveError(_("cannot extend multi option {0} if master or " - "slave").format(self.opt.impl_getname())) - index = getattr(self, '_index', None) - context = self._getcontext() - setting = context.cfgimpl_get_settings() - setting_properties = setting._getproperties(read_write=False) - if 'validator' in setting_properties and validate: - session = context.cfgimpl_get_values()._p_.getsession() - fake_context = context._gen_fake_values(session) - fake_multi = Multi(list(self), weakref.ref(fake_context), self.opt, self.path) - if index is None: - fake_multi.extend(iterable, validate=False) - self._validate(fake_multi, fake_context, index) - else: - fake_multi[index].extend(iterable, validate=False) - self._validate(fake_multi[index], fake_context, index) - super(Multi, self).extend(iterable) - self._store() - - def _validate(self, value, fake_context, force_index, submulti=False): - err = self.opt.impl_validate(value, context=fake_context, - force_index=force_index, - multi=self) - if err: - raise err - - def pop(self, index, force=False): - """the list value can be updated (poped) - only if the option is a master - - :param index: remove item a index - :type index: int - :param force: force pop item (without check master/slave) - :type force: boolean - :returns: item at index - """ - context = self._getcontext() - if not force: - if self.opt.impl_is_master_slaves('slave'): - 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(self.opt, - context.cfgimpl_get_values(), index) - #set value without valid properties - ret = super(Multi, self).pop(index) - self._store(force=force) - return ret - - def remove(self, value): - idx = self.index(value) - return self.pop(idx) - - def _store(self, force=False, index=None): - values = self._getcontext().cfgimpl_get_values() - if not force: - #FIXME could get properties an pass it - values.validate(self.opt, self, self.path, valid_masterslave=False) - values._setvalue(self.opt, self.path, self, index=index) - - -class SubMulti(Multi): - __slots__ = ('_index', 'refmulti') - - def __init__(self, value, context, opt, path, index): - """ - :param index: index (only for slave with submulti) - :type index: `int` - """ - self._index = index - super(SubMulti, self).__init__(value, context, opt, path) - - def append(self, value=undefined): - super(SubMulti, self).append(value, force=True) - - def pop(self, index): - return super(SubMulti, self).pop(index, force=True) - - def __setitem__(self, index, value): - self._setitem(index, value) - - def _store(self, force=False, index=None): - #force is unused here - values = self._getcontext().cfgimpl_get_values() - values.validate(self.opt, self, self.path, valid_masterslave=False) - multi = self.refmulti() - if multi is None: - multi = values._get_cached_value(self.opt, path=self.path) - multi[self._index] = self - values._setvalue(self.opt, self.path, multi) - - def _validate(self, value, fake_context, force_index, submulti=False): - if value is not None: - if submulti is False: - super(SubMulti, self)._validate(value, fake_context, - force_index, submulti) - else: - err = self.opt.impl_validate(value, context=fake_context, - force_index=self._index, - force_submulti_index=force_index, - multi=self) - if err: - raise err - - def _getdefaultvalue(self, index): - values = self._getcontext().cfgimpl_get_values() - return values._getdefaultvalue(self.opt, self.path, True, index, - self._index, True)