From e40a1e78a2bf757b3a18ae7a70d6beda46bd8295 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Sat, 2 Dec 2017 22:53:57 +0100 Subject: [PATCH] refactor masterslaves --- test/api/test_owner.py | 165 ++++++---- tiramisu/autolib.py | 9 +- tiramisu/config.py | 25 +- tiramisu/option/baseoption.py | 27 +- tiramisu/option/dynoptiondescription.py | 1 - tiramisu/option/masterslave.py | 336 +++------------------ tiramisu/option/option.py | 13 +- tiramisu/option/optiondescription.py | 97 +++--- tiramisu/option/syndynoptiondescription.py | 52 +++- tiramisu/storage/dictionary/value.py | 20 +- tiramisu/value.py | 8 +- 11 files changed, 296 insertions(+), 457 deletions(-) diff --git a/test/api/test_owner.py b/test/api/test_owner.py index eea0be6..dee383e 100644 --- a/test/api/test_owner.py +++ b/test/api/test_owner.py @@ -405,8 +405,13 @@ def _autocheck_get_value(api, path, conf, **kwargs): def autocheck_get_value(api, path, confread, confwrite, **kwargs): _set_value(api, path, confwrite, set_permissive=False, **kwargs) _autocheck_get_value(api, path, confread, set_permissive=False, **kwargs) + if path.endswith('val1'): + val2_path = path.replace('val1', 'val2') + _autocheck_default_value(api, val2_path, confread, **kwargs) if confread != confwrite: _autocheck_get_value(api, path, confwrite, set_permissive=False, **kwargs) + if path.endswith('val1'): + _autocheck_default_value(api, val2_path, confwrite, **kwargs) @autocheck @@ -528,7 +533,11 @@ def autocheck_append_value(api, path, confread, confwrite, **kwargs): len_new = len(new_master_value) assert len_value + 1 == len_new assert new_master_value[-1] == kwargs['default_multi'] - slave_path = path.rsplit('.', 1)[0] + '.third' + slave_path = path.rsplit('.', 1)[0] + if slave_path.endswith('val1') or slave_path.endswith('val2'): + slave_path += '.third' + slave_path[-4:] + else: + slave_path += '.third' for idx in range(len_new): assert api.forcepermissive.config(confread).option(slave_path, idx).value.get() == kwargs['default_multi'] # @@ -552,17 +561,21 @@ def autocheck_pop_value(api, path, confread, confwrite, **kwargs): if not kwargs.get('propertyerror', False): if not submulti_: values = ['value1', 'value2', 'value3', 'value4'] - slave = 'slave' + slave_value = 'slave' else: values = [['value1'], ['value2'], ['value3'], ['value4']] - slave = ['slave'] - slaves = [kwargs['default_multi'], slave, kwargs['default_multi'], kwargs['default_multi']] - a_slave = path.rsplit('.', 1)[0] + '.third' + slave_value = ['slave'] + slaves = [kwargs['default_multi'], slave_value, kwargs['default_multi'], kwargs['default_multi']] + a_slave = path.rsplit('.', 1)[0] + if a_slave.endswith('val1') or a_slave.endswith('val2'): + a_slave += '.third' + a_slave[-4:] + else: + a_slave += '.third' api.forcepermissive.config(confwrite).option(path).value.set(values) - api.forcepermissive.config(confwrite).option(a_slave, 1).value.set(slave) + api.forcepermissive.config(confwrite).option(a_slave, 1).value.set(slave_value) api.forcepermissive.config(confread).option(a_slave, 0).value.get() == kwargs['default_multi'] assert api.forcepermissive.config(confread).option(a_slave, 0).owner.isdefault() is True - api.forcepermissive.config(confread).option(a_slave, 1).value.get() == slave + api.forcepermissive.config(confread).option(a_slave, 1).value.get() == slave_value assert api.forcepermissive.config(confread).option(a_slave, 1).owner.isdefault() is False api.forcepermissive.config(confread).option(a_slave, 2).value.get() == kwargs['default_multi'] assert api.forcepermissive.config(confread).option(a_slave, 2).owner.isdefault() is True @@ -572,13 +585,13 @@ def autocheck_pop_value(api, path, confread, confwrite, **kwargs): api.forcepermissive.config(confwrite).option(path).value.pop(3) api.forcepermissive.config(confread).option(a_slave, 0).value.get() == kwargs['default_multi'] assert api.forcepermissive.config(confread).option(a_slave, 0).owner.isdefault() is True - api.forcepermissive.config(confread).option(a_slave, 1).value.get() == slave + api.forcepermissive.config(confread).option(a_slave, 1).value.get() == slave_value assert api.forcepermissive.config(confread).option(a_slave, 1).owner.isdefault() is False api.forcepermissive.config(confread).option(a_slave, 2).value.get() == kwargs['default_multi'] assert api.forcepermissive.config(confread).option(a_slave, 2).owner.isdefault() is True # api.forcepermissive.config(confwrite).option(path).value.pop(0) - api.forcepermissive.config(confread).option(a_slave, 0).value.get() == slave + api.forcepermissive.config(confread).option(a_slave, 0).value.get() == slave_value assert api.forcepermissive.config(confread).option(a_slave, 0).owner.isdefault() is False api.forcepermissive.config(confread).option(a_slave, 1).value.get() == kwargs['default_multi'] assert api.forcepermissive.config(confread).option(a_slave, 1).owner.isdefault() is True @@ -623,13 +636,15 @@ def autocheck_display(api, path, confread, confwrite, **kwargs): return make_dict = kwargs['make_dict'] make_dict_value = kwargs['make_dict_value'] + #print('--------') #print(make_dict) - #print(make_dict_value) #print(api.config(confread).config.make_dict()) assert api.config(confread).config.make_dict() == make_dict if confread != confwrite: assert(api.config(confwrite).config.make_dict()) == make_dict _set_value(api, path, confwrite, **kwargs) + #print('--') + #print(make_dict_value) #print(api.config(confread).config.make_dict()) assert api.config(confread).config.make_dict() == make_dict_value if confread != confwrite: @@ -1129,13 +1144,6 @@ def check_all(cfg, paths, path, meta, multi, default, default_multi, require, co else: default_value = value kwargs['default'] = default_value - if '.' in path: - if paths.get(path, {}) is None: - isslave = False - else: - isslave = paths.get(path, {}).get(path.rsplit('.', 1)[0], {}).get('master') is True and not path.endswith('.first') - if isslave and not multi is submulti: - kwargs['default'] = None is_dyn = False is_master = False @@ -1146,20 +1154,21 @@ def check_all(cfg, paths, path, meta, multi, default, default_multi, require, co break if '.' in cpath: dirname, name = cpath.split('.')[-2:] + for dname in cpath.split('.')[:-1]: + if options.get(dname, {}).get('dyn'): + is_dyn = True + if options.get(dname, {}).get('master'): + is_master = True else: dirname = '' name = cpath if options.get(dirname, {}).get('hidden'): continue - if options.get(dirname, {}).get('dyn'): - is_dyn = True - if options.get(dirname, {}).get('master'): - is_master = True - no_propertieserror = not options.get(name, {}).get('disabled') and not options.get(name, {}).get('hidden') allow_req = require and req + no_propertieserror = not options.get(name, {}).get('disabled') and not options.get(name, {}).get('hidden') if is_dyn: dyns.append(no_propertieserror or allow_req) - elif no_propertieserror or allow_req: + if not is_dyn and (no_propertieserror or allow_req): dico[cpath] = default_value if path == cpath: dico_value[cpath] = value @@ -1167,7 +1176,12 @@ def check_all(cfg, paths, path, meta, multi, default, default_multi, require, co dico_value[cpath] = default_value has_value = True - if is_dyn: + isslave = False + if '.' in path and is_master and not path.rsplit('.', 1)[1].startswith('first'): + isslave = True + if not multi is submulti: + kwargs['default'] = None + if is_dyn and dyns: idx = 0 for cpath in list(paths.keys())[len(dyns):]: if dyns[idx]: @@ -1198,18 +1212,30 @@ def check_all(cfg, paths, path, meta, multi, default, default_multi, require, co value = None if is_dyn: dico[cpath + 'extraoptconsistencyval1'] = value - dico[cpath[:-2] + '2.' + 'extraoptconsistencyval2'] = value dico_value[cpath + 'extraoptconsistencyval1'] = value - dico_value[cpath[:-2] + '2.' + 'extraoptconsistencyval2'] = value + if is_master: + spath = cpath.split('.') + spath[-2] = spath[-2][:-1] + '2' + spath[-3] = spath[-3][:-1] + '2' + npath = '.'.join(spath) + 'extraoptconsistencyval2' + else: + npath = cpath[:-2] + '2.' + 'extraoptconsistencyval2' + dico[npath] = value + dico_value[npath] = value else: dico[cpath + 'extraoptconsistency'] = value dico_value[cpath + 'extraoptconsistency'] = value if is_master: for cpath in list(paths.keys())[len(dyns):]: - if cpath.endswith('.first'): + if cpath.endswith('.first') or cpath.endswith('.firstval1') or cpath.endswith('.firstval2'): second_path = cpath.rsplit('.', 1)[0] + '.second' third_path = cpath.rsplit('.', 1)[0] + '.third' cons_path = cpath.rsplit('.', 1)[0] + '.extraoptconsistency' + if is_dyn: + suffix = cpath[-4:] + second_path += suffix + third_path += suffix + cons_path += suffix # if default_multi: if multi is not submulti: @@ -1237,11 +1263,9 @@ def check_all(cfg, paths, path, meta, multi, default, default_multi, require, co dico_value[second_path] = [dvalue] * len_master if third_path in dico_value: dico_value[third_path] = [dvalue] * len_master - cons_path = cpath.rsplit('.', 1)[0] + '.extraoptconsistency' if cons_path in dico_value: dico_value[cons_path] = [dvalue] * len_master - break - return dico, dico_value + return is_dyn, dico, dico_value if DISPLAY: text = u' {} launch tests for {}'.format(ICON, path) if multi is True: @@ -1267,7 +1291,7 @@ def check_all(cfg, paths, path, meta, multi, default, default_multi, require, co confwrite = confread = None idx = 0 for req in requires: - kwargs['make_dict'], kwargs['make_dict_value'] = _build_make_dict() + is_dyn, kwargs['make_dict'], kwargs['make_dict_value'] = _build_make_dict() kwargs['callback'] = callback for func in autocheck_registers: cfg_name = 'conftest' + str(idx) @@ -1283,6 +1307,11 @@ def check_all(cfg, paths, path, meta, multi, default, default_multi, require, co if api.unrestraint.option(path).option.isslave(): dirname = path.rsplit('.', 1)[0] master_path = dirname + '.first' + master_path_2 = None + if dirname.endswith('val1') or dirname.endswith('val2'): + master_path += 'val1' + master_path = master_path.replace('val2', 'val1') + master_path_2 = master_path.replace('val1', 'val2') if multi is submulti: value = SUBLIST_SECOND_VALUE else: @@ -1290,6 +1319,10 @@ def check_all(cfg, paths, path, meta, multi, default, default_multi, require, co api.option(master_path).value.set(value) ckwargs['make_dict'][master_path] = value ckwargs['make_dict_value'][master_path] = value + if master_path_2: + api.option(master_path_2).value.set(value) + ckwargs['make_dict'][master_path_2] = value + ckwargs['make_dict_value'][master_path_2] = value if default_multi: if multi is not submulti: dvalue = SECOND_VALUE @@ -1299,19 +1332,33 @@ def check_all(cfg, paths, path, meta, multi, default, default_multi, require, co dvalue = [] else: dvalue = None - if dirname + '.second' in ckwargs['make_dict']: - ckwargs['make_dict'][dirname + '.second'] = [dvalue] * len(value) - ckwargs['make_dict_value'][dirname + '.second'] = [dvalue] * len(value) - if path == dirname + '.second': - ckwargs['make_dict_value'][dirname + '.second'][-1] = ckwargs['make_dict_value'][master_path][-1] - if dirname + '.third' in ckwargs['make_dict']: - ckwargs['make_dict'][dirname + '.third'] = [dvalue] * len(value) - ckwargs['make_dict_value'][dirname + '.third'] = [dvalue] * len(value) - if path == dirname + '.third': - ckwargs['make_dict_value'][dirname + '.third'][-1] = ckwargs['make_dict_value'][master_path][-1] - if dirname + '.extraoptconsistency' in ckwargs['make_dict']: - ckwargs['make_dict'][dirname + '.extraoptconsistency'] = [dvalue] * len(value) - ckwargs['make_dict_value'][dirname + '.extraoptconsistency'] = [dvalue] * len(value) + def do(suffix, oldsuffix=None): + if suffix: + ldirname = dirname.replace(oldsuffix, suffix) + else: + ldirname = dirname + npath = ldirname + '.second' + suffix + if npath in ckwargs['make_dict']: + ckwargs['make_dict'][npath] = [dvalue] * len(value) + ckwargs['make_dict_value'][npath] = [dvalue] * len(value) + if path == npath: + ckwargs['make_dict_value'][npath][-1] = ckwargs['make_dict_value'][master_path][-1] + npath = ldirname + '.third' + suffix + if npath in ckwargs['make_dict']: + ckwargs['make_dict'][npath] = [dvalue] * len(value) + ckwargs['make_dict_value'][npath] = [dvalue] * len(value) + if path == npath: + ckwargs['make_dict_value'][npath][-1] = ckwargs['make_dict_value'][master_path][-1] + npath = ldirname + '.extraoptconsistency' + suffix + if npath in ckwargs['make_dict']: + ckwargs['make_dict'][npath] = [dvalue] * len(value) + ckwargs['make_dict_value'][npath] = [dvalue] * len(value) + if not is_dyn: + do('') + else: + #do(dirname[-4:]) + do('val1', 'val2') + do('val2', 'val1') #FIXME devrait etre dans la config ca ... api.read_write() @@ -1478,11 +1525,15 @@ def make_conf(options, meta, multi, default, default_multi, require, consistency local_collect_options = local_collect_options[optiondescription] local_collect_options['properties'].update(option.get(optiondescription, {})) option_name = path.split('.')[-1] + in_master = False if '.' in path: name_od = path.rsplit('.', 1)[0] - else: - name_od = '' - in_master = collect_options.get(name_od, {}).get('properties', {}).get('master') + if '.' in name_od: + subod, name_od = name_od.split('.') + oddescr = collect_options.get(subod, {}) + else: + oddescr = collect_options + in_master = oddescr.get(name_od, {}).get('properties', {}).get('master') master = in_master and path.endswith('first') obj, objcall = make_option(option_name, option.get(option_name), in_master, master) if obj is None: @@ -1517,18 +1568,10 @@ DICT_PATHS = [ ('second', {'second': {'disabled': True}}), ('third', {'third': {'hidden': True}}) ]), - #test a config with an optiondescription - 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.second', {'second': {'disabled': True}}), ('subod.subsubod.third', {'third': {'hidden': True}})]), - #test a config with mix of different optiondescription - OrderedDict([('first', {}), - ('subod.second', {'second': {'disabled': True}}), - ('subod.subsubod.third', {'third': {'hidden': True}})]), #test a config with masterslaves OrderedDict([('odmaster.first', {'odmaster': {'master': True}}), ('odmaster.second', {'odmaster': {'master': True}, 'second': {'disabled': True, 'slave': True}}), @@ -1566,7 +1609,17 @@ DICT_PATHS = [ ('subod.subsubodval1.thirdval1', None), ('subod.subsubodval2.firstval2', None), ('subod.subsubodval2.secondval2', None), - ('subod.subsubodval2.thirdval2', None)]) + ('subod.subsubodval2.thirdval2', None)]), + #test a config with dyn subsubod with masterslave + OrderedDict([('subod.subsubod.first', {'subod': {'dyn': True}, 'subsubod': {'master': True}}), + ('subod.subsubod.second', {'subod': {'dyn': True}, 'subsubod' : {'master': True}, 'second': {'disabled': True, 'slave': True}}), + ('subod.subsubod.third', {'subod': {'dyn': True}, 'subsubod': {'master': True}, 'third': {'hidden': True, 'slave': True}}), + ('subodval1.subsubodval1.firstval1', None), + ('subodval1.subsubodval1.secondval1', None), + ('subodval1.subsubodval1.thirdval1', None), + ('subodval2.subsubodval2.firstval2', None), + ('subodval2.subsubodval2.secondval2', None), + ('subodval2.subsubodval2.thirdval2', None)]), ] diff --git a/tiramisu/autolib.py b/tiramisu/autolib.py index 6d0937c..500f99f 100644 --- a/tiramisu/autolib.py +++ b/tiramisu/autolib.py @@ -21,6 +21,7 @@ from .error import PropertiesOptionError, ConfigError, SlaveError, display_list from .i18n import _ from .setting import undefined +from .option.baseoption import DynSymLinkOption from .storage import get_default_values_storages, get_default_settings_storages # ____________________________________________________________ @@ -166,10 +167,10 @@ def carry_out_calculation(option, # callbk is something link (opt, True|False) opt, force_permissive = callbk if opt._is_subdyn(): - root = '.'.join(option.impl_getpath(context).split('.')[:-1]) - name = opt.impl_getname() + option.impl_getsuffix() - path = root + '.' + name - opt = opt._impl_to_dyn(name, path) + opt = DynSymLinkOption(opt, + option._rootpath, + option.impl_getsuffix()) + path = opt.impl_getpath(context) else: path = context.cfgimpl_get_description( ).impl_get_path_by_opt(opt) diff --git a/tiramisu/config.py b/tiramisu/config.py index 54b9141..73c791d 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -83,10 +83,17 @@ class SubConfig(object): if setting_properties is not undefined: self._impl_setting_properties = setting_properties if setting_properties is not None and descr.impl_get_group_type() == groups.master: - self._impl_length = descr.get_length(context().cfgimpl_get_values(), - setting_properties=setting_properties, - validate=validate, - force_permissive=force_permissive) + master = descr.getmaster() + context_ = context() + masterp = master.impl_getpath(context_) + value = context_.cfgimpl_get_values().get_cached_value(master, + path=masterp, + validate=validate, + force_permissive=force_permissive, + self_properties=undefined, + index=None, + setting_properties=setting_properties) + self._impl_length = len(value) def cfgimpl_get_length(self): return getattr(self, '_impl_length') @@ -317,7 +324,7 @@ class SubConfig(object): setting_properties=setting_properties) child = self.cfgimpl_get_description().impl_getchild(name, setting_properties, - context) + self) if isinstance(child, (OptionDescription, SynDynOptionDescription)): raise TypeError(_("can't assign to an OptionDescription")) # pragma: optional cover elif child.impl_is_symlinkoption() and \ @@ -350,7 +357,7 @@ class SubConfig(object): setting_properties=setting_properties) child = self.cfgimpl_get_description().impl_getchild(name, setting_properties, - context) + self) if isinstance(child, (OptionDescription, SynDynOptionDescription)): raise TypeError(_("can't delete an OptionDescription")) # pragma: optional cover elif child.impl_is_symlinkoption() and \ @@ -411,8 +418,8 @@ class SubConfig(object): context = self._cfgimpl_get_context() option = self.cfgimpl_get_description().impl_getchild(name, - context, - setting_properties) + setting_properties, + self) if option.impl_is_symlinkoption() and isinstance(option, DynSymLinkOption): # FIXME peuvent-il vraiment etre le 2 ? # si non supprimer tout ces tests inutiles @@ -832,7 +839,7 @@ class _CommonConfig(SubConfig): setting_properties=setting_properties) option = self.cfgimpl_get_description().impl_getchild(path, setting_properties, - self._cfgimpl_get_context()) + self) if not validate_properties: return option else: diff --git a/tiramisu/option/baseoption.py b/tiramisu/option/baseoption.py index 8a6d984..7a3f043 100644 --- a/tiramisu/option/baseoption.py +++ b/tiramisu/option/baseoption.py @@ -634,15 +634,17 @@ class SymLinkOption(OnlyOption): class DynSymLinkOption(object): - __slots__ = ('_dyn', '_opt', '_name') + __slots__ = ('_rootpath', + '_opt', + '_suffix') def __init__(self, - name, opt, - dyn): - self._name = name - self._dyn = dyn + rootpath, + suffix): self._opt = opt + self._rootpath = rootpath + self._suffix = suffix def __getattr__(self, name, @@ -650,7 +652,7 @@ class DynSymLinkOption(object): return getattr(self.impl_getopt(), name) def impl_getname(self): - return self._name + return self._opt.impl_getname() + self._suffix def impl_get_display_name(self): return self.impl_getopt().impl_get_display_name(dyn_name=self.impl_getname()) @@ -659,18 +661,13 @@ class DynSymLinkOption(object): return self._opt def impl_getsuffix(self): - return self._dyn.split('.')[-1][len(self.impl_getopt().impl_getname()):] + return self._suffix def impl_getpath(self, context): - path = self.impl_getopt().impl_getpath(context) - base_path = '.'.join(path.split('.')[:-2]) - if self.impl_is_master_slaves() and base_path is not '': - base_path = base_path + self.impl_getsuffix() - if base_path == '': - return self._dyn - else: - return base_path + '.' + self._dyn + if self._rootpath == '': + return self.impl_getname() + return self._rootpath + '.' + self.impl_getname() def impl_validate(self, value, diff --git a/tiramisu/option/dynoptiondescription.py b/tiramisu/option/dynoptiondescription.py index ac48574..0999266 100644 --- a/tiramisu/option/dynoptiondescription.py +++ b/tiramisu/option/dynoptiondescription.py @@ -91,4 +91,3 @@ class DynOptionDescription(OptionDescription): '').format(val, self.impl_get_display_name())) return values - diff --git a/tiramisu/option/masterslave.py b/tiramisu/option/masterslave.py index f06b3a1..dd393ac 100644 --- a/tiramisu/option/masterslave.py +++ b/tiramisu/option/masterslave.py @@ -49,30 +49,32 @@ class MasterSlaves(OptionDescription): master = children[0] if not children: raise ValueError(_('children is mandatory in masterslaves "{}"').format(name)) - for child in children[1:]: - if child.impl_getdefault() != []: - raise ValueError(_("not allowed default value for option {0} " - "in master/slave object {1}").format(child.impl_getname(), - name)) - slaves.append(child) - child._add_dependency(self) for idx, child in enumerate(children): + if idx != 0 and child.impl_getdefault() != []: + raise ValueError(_('not allowed default value for option "{0}" ' + 'in master/slave object "{1}"' + '').format(child.impl_get_display_name(), + self.impl_get_display_name())) if child.impl_is_symlinkoption(): # pragma: optional cover - raise ValueError(_("master group {0} shall not have " - "a symlinkoption").format(self.impl_getname())) + raise ValueError(_('master group "{0}" shall not have ' + "a symlinkoption").format(self.impl_get_display_name())) if not isinstance(child, Option): # pragma: optional cover - raise ValueError(_("master group {0} shall not have " - "a subgroup").format(self.impl_getname())) + raise ValueError(_('master group "{0}" shall not have ' + 'a subgroup').format(self.impl_get_display_name())) if not child.impl_is_multi(): # pragma: optional cover - raise ValueError(_("not allowed option {0} " - "in group {1}" - ": this option is not a multi" - "").format(child.impl_getname(), self.impl_getname())) + raise ValueError(_('not allowed option "{0}" ' + 'in group "{1}"' + ': this option is not a multi' + '').format(child.impl_get_display_name(), + self.impl_get_display_name())) # no empty property for save if idx != 0: properties = list(child._properties) properties.remove('empty') child._properties = tuple(properties) + slaves.append(child) + child._add_dependency(self) + child._master_slaves = weakref.ref(self) callback, callback_params = master.impl_get_callback() if callback is not None and callback_params != {}: for callbacks in callback_params.values(): @@ -81,37 +83,18 @@ class MasterSlaves(OptionDescription): if callbk[0] in slaves: raise ValueError(_("callback of master's option shall " "not refered a slave's ones")) - #everything is ok, store references - for child in children: - child._master_slaves = weakref.ref(self) - master._add_dependency(self) def is_master(self, opt): master = self._children[0][0] return opt.impl_getname() == master or (opt.impl_is_dynsymlinkoption() and opt._opt.impl_getname() == master) - def getmaster(self, opt): - master = self._children[1][0] - if opt is not None and opt.impl_is_dynsymlinkoption(): - suffix = opt.impl_getsuffix() - name = master.impl_getname() + suffix - base_path = opt._dyn.split('.')[0] + '.' - path = base_path + name - master = master._impl_to_dyn(name, path) - return master + def getmaster(self): + return self._children[1][0] - def getslaves(self, opt): - if opt.impl_is_dynsymlinkoption(): - for slave in self._children[1][1:]: - suffix = opt.impl_getsuffix() - name = slave.impl_getname() + suffix - base_path = opt._dyn.split('.')[0] + '.' - path = base_path + name - yield slave._impl_to_dyn(name, path) - else: - for slave in self._children[1][1:]: - yield slave + def getslaves(self): + for slave in self._children[1][1:]: + yield slave def in_same_group(self, opt): if opt.impl_is_dynsymlinkoption(): @@ -127,7 +110,7 @@ class MasterSlaves(OptionDescription): _commit=True, force_permissive=False): - for slave in self.getslaves(opt): + for slave in self.getslaves(): slave_path = slave.impl_getpath(values._getcontext()) values.reset(slave, slave_path, @@ -137,15 +120,17 @@ class MasterSlaves(OptionDescription): force_permissive=force_permissive) def pop(self, - opt, - path, values, index, setting_properties, - force_permissive=False): + force_permissive, + slaves=undefined): - for slave in self.getslaves(opt): - slave_path = slave.impl_getpath(values._getcontext()) + context = values._getcontext() + if slaves is undefined: + slaves = self.getslaves() + for slave in slaves: + slave_path = slave.impl_getpath(context) slavelen = values._p_.get_max_length(slave_path) if not values.is_default_owner(slave, slave_path, @@ -153,13 +138,6 @@ class MasterSlaves(OptionDescription): validate_meta=False, index=index, force_permissive=force_permissive): - #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) @@ -168,214 +146,6 @@ class MasterSlaves(OptionDescription): values._p_.reduce_index(slave_path, idx) - - 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, - force_permissive, - validate_properties, - self_properties, - index, - setting_properties, - check_frozen) - else: - return self._getslave(values, - opt, - path, - validate, - force_permissive, - trusted_cached_properties, - validate_properties, - setting_properties, - self_properties, - index, - 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, - self_properties=self_properties, - index=index, - setting_properties=setting_properties) - - def _getslave(self, values, opt, path, validate, force_permissive, - trusted_cached_properties, validate_properties, setting_properties, - self_properties, index, check_frozen): - """ - if master has length 0: - return [] - if master has length bigger than 0: - if default owner: - if has callback: - if return a list: - list same length as master: return list - list is smaller than master: return list + None - list is greater than master: raise SlaveError - if has default value: - list same length as master: return list - list is smaller than master: return list + None - list is greater than master: raise SlaveError - if has default_multi value: - return default_multi * master's length - if has value: - list same length as master: return list - list is smaller than master: return list + None - list is greater than master: raise SlaveError - """ - master = self.getmaster(opt) - context = values._getcontext() - masterp = master.impl_getpath(context) - try: - 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) - except PropertiesOptionError as mastervalue: - mastervalue.set_orig_opt(opt) - raise mastervalue - masterlen = len(mastervalue) - #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, - value=multi, - path=path, - force_permissive=force_permissive, - setting_properties=setting_properties) - if props: - return props - #FIXME shouldn't have index!!! - if index is None: - indexes = range(0, masterlen) - else: - indexes = [index] - for idx in indexes: - try: - 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) - except PropertiesOptionError as perr: - err = perr - if index is None: - multi.append(err) - else: - multi = err - if index is None: - multi.append(value) - else: - multi = value - return multi - - 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) - else: - 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) - - 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(values._getcontext()) - value = self._getmaster(values, - master, - masterp, - validate, - force_permissive, - validate, - undefined, - None, - setting_properties, - False) - if isinstance(value, Exception): - return value - return len(value) - - def validate_slave_length(self, - masterlen, - valuelen, - name, - opt, - setitem=False): - if valuelen > masterlen or (valuelen < masterlen and setitem): - if debug: # pragma: no cover - log.debug('validate_slave_length: masterlen: {0}, valuelen: {1}, ' - 'setitem: {2}'.format(masterlen, valuelen, setitem)) - if not opt.impl_is_master_slaves('master'): - opt = self.getmaster(opt) - raise SlaveError(_("invalid len for the slave: {0}" - " which has {1} as master").format( - name, opt.impl_getname())) - def reset_cache(self, opt, path, @@ -384,14 +154,14 @@ class MasterSlaves(OptionDescription): resetted_opts): context = obj._getcontext() #FIXME pb avec dyn, devrait etre une option - mopt = self.getmaster(None) + mopt = self.getmaster() mpath = mopt.impl_getpath(context) mopt.reset_cache(mopt, mpath, obj, type_, resetted_opts) - for slave in self.getslaves(mopt): + for slave in self.getslaves(): spath = slave.impl_getpath(context) slave.reset_cache(slave, spath, @@ -399,45 +169,6 @@ class MasterSlaves(OptionDescription): type_, resetted_opts) - def impl_getchild(self, - name, - setting_properties, - context=undefined, - dyn=True): - return super(MasterSlaves, self).impl_getchild(name, - setting_properties, - context, - dyn) - - def impl_validate(self, - context, - force_permissive, - setting_properties, - masterlen=None, - slavelen=None, - opt=None, - setitem=False): - values = context.cfgimpl_get_values() - if masterlen is None: - master = self.getmaster(opt) - masterp = master.impl_getpath(context) - - 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) - else: - master = opt - if slavelen is not None: - self.validate_slave_length(masterlen, slavelen, opt.impl_getname(), master, setitem=setitem) - else: - for slave in self.getslaves(master): - slave_path = slave.impl_getpath(context) - 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, @@ -446,3 +177,6 @@ class MasterSlaves(OptionDescription): if len(value) < context._impl_length: return ValueError(_('cannot reduce length of master "{}"' '').format(option.impl_get_display_name())) + + def is_masterslaves(self): + return True diff --git a/tiramisu/option/option.py b/tiramisu/option/option.py index 0037ce5..3e80dcf 100644 --- a/tiramisu/option/option.py +++ b/tiramisu/option/option.py @@ -629,9 +629,9 @@ class Option(OnlyOption): suffix = option.impl_getname()[namelen:] opts = [] for opt in all_cons_opts: - name = opt.impl_getname() + suffix - path = subpath + '.' + name - opts.append(opt._impl_to_dyn(name, path)) + opts.append(DynSymLinkOption(opt, + subpath, + suffix)) else: opts = all_cons_opts err = opts[0]()._launch_consistency(self, @@ -685,13 +685,6 @@ class Option(OnlyOption): warnings_only): pass - def _impl_to_dyn(self, - name, - path): - return DynSymLinkOption(name, - self, - dyn=path) - def impl_getdefault_multi(self): "accessing the default value for a multi" if self.impl_is_submulti(): diff --git a/tiramisu/option/optiondescription.py b/tiramisu/option/optiondescription.py index 5b107ea..17d4487 100644 --- a/tiramisu/option/optiondescription.py +++ b/tiramisu/option/optiondescription.py @@ -24,7 +24,7 @@ from copy import copy from ..i18n import _ from ..setting import groups, undefined, owners from .baseoption import BaseOption -from .option import ALLOWED_CONST_LIST +from .option import ALLOWED_CONST_LIST, DynSymLinkOption from .syndynoptiondescription import SynDynOptionDescription from ..error import ConfigError, ConflictError @@ -145,7 +145,9 @@ class CacheOptionDescription(BaseOption): self._set_readonly() def impl_already_build_caches(self): - return getattr(self, '_cache_paths', None) is not None + if hasattr(self, '_cache_paths'): + return True + return False def impl_build_force_store_values(self, config, @@ -202,8 +204,7 @@ class CacheOptionDescription(BaseOption): cache_option) _currpath.pop() if save: - _setattr = object.__setattr__ - _setattr(self, '_cache_paths', (tuple(cache_option), tuple(cache_path))) + self._cache_paths = (tuple(cache_option), tuple(cache_path)) class OptionDescriptionWalk(CacheOptionDescription): @@ -250,8 +251,13 @@ class OptionDescriptionWalk(CacheOptionDescription): path = _rebuild_dynpath(path, suffix, subdyn) - option = option._impl_to_dyn(name + suffix, - path) + if '.' in path: + subpath = path.rsplit('.', 1)[0] + else: + subpath = '' + option = DynSymLinkOption(option, + subpath, + suffix) break if not found: return False @@ -272,11 +278,17 @@ class OptionDescriptionWalk(CacheOptionDescription): name = option.impl_getname() for suffix in option._subdyn._impl_get_suffixes(context, setting_properties): - spath = _rebuild_dynpath(path, - suffix, - option._subdyn) - find_results.append((spath, option._impl_to_dyn( - name + suffix, spath))) + path = _rebuild_dynpath(path, + suffix, + option._subdyn) + if '.' in path: + subpath = path.rsplit('.', 1)[0] + else: + subpath = '' + doption = DynSymLinkOption(option, + subpath, + suffix) + find_results.append((subpath, doption)) else: find_results.append((path, option)) return True @@ -302,11 +314,17 @@ class OptionDescriptionWalk(CacheOptionDescription): name = option.impl_getname() for suffix in option._subdyn._impl_get_suffixes(context, setting_properties): - spath = _rebuild_dynpath(path, - suffix, + path = _rebuild_dynpath(path, + suffix, option._subdyn) - find_results.append((spath, option._impl_to_dyn(name + suffix, - spath))) + if '.' in path: + subpath = path.rsplit('.', 1)[0] + else: + subpath = '' + doption = DynSymLinkOption(option, + subpath, + suffix) + find_results.append((path, doption)) else: find_results.append((path, option)) else: @@ -319,18 +337,17 @@ class OptionDescriptionWalk(CacheOptionDescription): def impl_getchild(self, name, setting_properties, - context=undefined, - dyn=True): - if name not in self._children[0]: - child = self._impl_search_dynchild(name, - context=context, - setting_properties=setting_properties) - if child: - return child - else: + subconfig): + if name in self._children[0]: child = self._children[1][self._children[0].index(name)] if not child.impl_is_dynoptiondescription(): return child + else: + child = self._impl_search_dynchild(name, + subconfig=subconfig, + setting_properties=setting_properties) + if child: + return child raise AttributeError(_('unknown Option {0} ' 'in OptionDescription {1}' '').format(name, self.impl_getname())) @@ -340,7 +357,7 @@ class OptionDescriptionWalk(CacheOptionDescription): if getattr(self, '_cache_paths', None) is None: raise ConfigError(_('use impl_get_opt_by_path only with root OptionDescription')) if path not in self._cache_paths[1]: - raise AttributeError(_('no option for path {0}').format(path)) + raise AttributeError(_('no option for path "{}"').format(path)) return self._cache_paths[0][self._cache_paths[1].index(path)] def impl_get_path_by_opt(self, @@ -348,7 +365,7 @@ class OptionDescriptionWalk(CacheOptionDescription): if getattr(self, '_cache_paths', None) is None: raise ConfigError(_('use impl_get_path_by_opt only with root OptionDescription')) if opt not in self._cache_paths[0]: - raise AttributeError(_('no option {0} found').format(opt)) + raise AttributeError(_('no option "{}" found').format(opt)) return self._cache_paths[1][self._cache_paths[0].index(opt)] def impl_getchildren(self, @@ -374,37 +391,30 @@ class OptionDescriptionWalk(CacheOptionDescription): def _impl_search_dynchild(self, name, - context, + subconfig, setting_properties): for child in self._impl_st_getchildren(only_dyn=True): cname = child.impl_getname() if name.startswith(cname): - for value in child._impl_get_suffixes(context, + for value in child._impl_get_suffixes(subconfig._cfgimpl_get_context(), setting_properties): if name == cname + value: return SynDynOptionDescription(child, - name, + subconfig.cfgimpl_get_path(), value) - def __getattr__(self, - name, - context=undefined, - setting_properties=undefined): - if name.startswith('_'): - return object.__getattribute__(self, - name) def _impl_get_dynchild(self, child, - suffix): - name = child.impl_getname() + suffix - path = self.impl_getname() + suffix + '.' + name + suffix, + subpath): if isinstance(child, OptionDescription): return SynDynOptionDescription(child, - name, + subpath, suffix) else: - return child._impl_to_dyn(name, - path) + return DynSymLinkOption(child, + subpath, + suffix) class OptionDescription(OptionDescriptionWalk): @@ -456,6 +466,9 @@ class OptionDescription(OptionDescriptionWalk): # the group_type is useful for filtering OptionDescriptions in a config self._group_type = groups.default + def is_masterslaves(self): + return False + def impl_getdoc(self): return self.impl_get_information('doc') diff --git a/tiramisu/option/syndynoptiondescription.py b/tiramisu/option/syndynoptiondescription.py index a9facfb..3438fff 100644 --- a/tiramisu/option/syndynoptiondescription.py +++ b/tiramisu/option/syndynoptiondescription.py @@ -20,20 +20,21 @@ # ____________________________________________________________ from ..i18n import _ from ..setting import undefined +from .baseoption import DynSymLinkOption class SynDynOptionDescription(object): __slots__ = ('_opt', - '_name', + '_subpath', '_suffix') def __init__(self, opt, - name, + subpath, suffix): self._opt = opt - self._name = name + self._subpath = subpath self._suffix = suffix def __getattr__(self, name): @@ -42,18 +43,19 @@ class SynDynOptionDescription(object): def impl_getchild(self, name, setting_properties, - context): + subconfig): if name.endswith(self._suffix): oname = name[:-len(self._suffix)] child = self._children[1][self._children[0].index(oname)] return self._impl_get_dynchild(child, - self._suffix) + self._suffix, + subconfig.cfgimpl_get_path()) raise AttributeError(_('unknown Option {0} ' 'in SynDynOptionDescription {1}' '').format(name, self.impl_getname())) def impl_getname(self): - return self._name + return self._opt.impl_getname() + self._suffix def impl_getchildren(self, setting_properties, @@ -62,13 +64,39 @@ class SynDynOptionDescription(object): children = [] for child in self._opt.impl_getchildren(setting_properties): yield(self._opt._impl_get_dynchild(child, - self._suffix)) + self._suffix, + self._subpath)) - def impl_getpath(self, context): - path = self.impl_getopt().impl_getpath(context).split('.') - path[-1] += self._suffix - path.append(self._name) - return '.'.join(path) + def impl_getpath(self): + subpath = self._subpath + if subpath != '': + subpath += '.' + return subpath + self.impl_getname() def impl_getopt(self): return self._opt + + def getmaster(self): + master = self._opt.getmaster() + return DynSymLinkOption(master, + self.impl_getpath(), + self._suffix) + + def getslaves(self): + subpath = self.impl_getpath() + for slave in self._opt.getslaves(): + yield DynSymLinkOption(slave, + subpath, + self._suffix) + + def pop(self, + values, + index, + setting_properties, + force_permissive, + slaves=undefined): + self._opt.pop(values, + index, + setting_properties, + force_permissive, + slaves=self.getslaves()) diff --git a/tiramisu/storage/dictionary/value.py b/tiramisu/storage/dictionary/value.py index d23e215..4576547 100644 --- a/tiramisu/storage/dictionary/value.py +++ b/tiramisu/storage/dictionary/value.py @@ -20,6 +20,10 @@ from ...setting import undefined from ...i18n import _ +DEBUG = True +DEBUG = False + + class Values(Cache): __slots__ = ('_values', '_informations', '__weakref__') @@ -71,8 +75,8 @@ class Values(Cache): """set value for a path a specified value must be associated to an owner """ - if value == 'y': - raise Exception('pouet') + if DEBUG: + print('setvalue', path, value, index) values = [] vidx = None @@ -93,6 +97,10 @@ class Values(Cache): return: boolean """ has_path = path in self._values[0] + if path.startswith('subod.subodval'): + raise Exception('arf ...') + if DEBUG: + print('hasvalue', path, index, has_path) if index is None: return has_path elif has_path: @@ -105,6 +113,8 @@ class Values(Cache): """ _values == ((path1, path2), ((idx1_1, idx1_2), None), ((value1_1, value1_2), value2), ((owner1_1, owner1_2), owner2)) """ + if DEBUG: + print('reduce_index', path, index) path_idx = self._values[0].index(path) indexes = self._values[1][path_idx] if index in indexes: @@ -118,6 +128,8 @@ class Values(Cache): self._values = tuple(values) def resetvalue_index(self, path, index): + if DEBUG: + print('resetvalue_index', path, index) def _resetvalue(nb): values_idx = list(values[nb]) del(values_idx[path_idx]) @@ -149,6 +161,8 @@ class Values(Cache): def resetvalue(self, path, commit): """remove value means delete value in storage """ + if DEBUG: + print('resetvalue', path) def _resetvalue(nb): lst = list(self._values[nb]) lst.pop(idx) @@ -217,6 +231,8 @@ class Values(Cache): with_value) if owner is undefined: owner = default + if DEBUG: + print('getvalue', path, index, value) if with_value: return owner, value else: diff --git a/tiramisu/value.py b/tiramisu/value.py index f09ccca..4d2e6fe 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -489,7 +489,7 @@ class Values(object): if meta is None: return False if opt.impl_is_master_slaves('slave'): - master = opt.impl_get_master_slaves().getmaster(opt) + master = opt.impl_get_master_slaves().getmaster() masterp = master.impl_getpath(context) # slave could be a "meta" only if master hasn't value if self._p_.hasvalue(masterp, @@ -714,12 +714,10 @@ class Values(object): index=None, setting_properties=setting_properties, _commit=True) - subconfig.cfgimpl_get_description().pop(opt, - path, - self, + subconfig.cfgimpl_get_description().pop(self, index, setting_properties, - force_permissive=force_permissive) + force_permissive) #______________________________________________________________________ # information