diff --git a/test/test_dyn_optiondescription.py b/test/test_dyn_optiondescription.py index 03ba3fa..62889fb 100644 --- a/test/test_dyn_optiondescription.py +++ b/test/test_dyn_optiondescription.py @@ -118,8 +118,8 @@ def test_getdoc_dyndescription(): assert api.option('od.dodval2').option.name() == 'dodval2' assert api.option('od.dodval1.stval1').option.doc() == 'doc1' assert api.option('od.dodval2.stval2').option.doc() == 'doc1' - assert api.option('od.dodval1').option.doc() == 'doc2' - assert api.option('od.dodval2').option.doc() == 'doc2' + assert api.option('od.dodval1').option.doc() == 'doc2val1' + assert api.option('od.dodval2').option.doc() == 'doc2val2' def test_mod_dyndescription(): @@ -542,6 +542,35 @@ def test_requires_dyndescription(): assert frozenset(props) == frozenset(['disabled']) +def test_requires_dyndescription_in_dyn(): + boolean = BoolOption('boolean', '', True) + st = StrOption('st', '', requires=[{'option': boolean, 'expected': False, + 'action': 'disabled'}]) + dod = DynOptionDescription('dod', '', [boolean, st], callback=return_list) + od = OptionDescription('od', '', [dod]) + od2 = OptionDescription('od', '', [od]) + cfg = Config(od2) + cfg.property.read_write() + + assert cfg.option('od.dodval1.stval1').value.get() is None + assert cfg.option('od.dodval2.stval2').value.get() is None + # + cfg.option('od.dodval1.booleanval1').value.set(False) + + props = [] + try: + cfg.option('od.dodval1.stval1').value.get() + except PropertiesOptionError as err: + props = err.proptype + assert props == frozenset(['disabled']) + props = [] + cfg.option('od.dodval2.stval2').value.get() + # + cfg.option('od.dodval1.booleanval1').value.set(True) + assert cfg.option('od.dodval1.stval1').value.get() is None + assert cfg.option('od.dodval2.stval2').value.get() is None + + def test_requires_dyndescription2(): boolean = BoolOption('boolean', '', True) st1 = StrOption('st', '') @@ -920,6 +949,219 @@ def test_masterslaves_dyndescription(): assert api.option('od.stval2.st1val2.st1val2').owner.isdefault() +def test_masterslaves_default_multi_dyndescription(): + st1 = StrOption('st1', "", multi=True) + st2 = StrOption('st2', "", multi=True, default_multi='no') + stm = MasterSlaves('st1', '', [st1, st2]) + st = DynOptionDescription('st', '', [stm], callback=return_list) + od = OptionDescription('od', '', [st]) + od2 = OptionDescription('od', '', [od]) + api = Config(od2) + owner = api.owner.get() + # + assert api.option('od.stval1.st1val1.st1val1').value.get() == [] + assert api.option('od.stval2.st1val2.st1val2').value.get() == [] + assert api.option('od.stval1.st1val1.st1val1').owner.isdefault() + assert api.option('od.stval2.st1val2.st1val2').owner.isdefault() + # + api.option('od.stval1.st1val1.st1val1').value.set(['yes']) + assert api.option('od.stval1.st1val1.st1val1').value.get() == ['yes'] + assert api.option('od.stval1.st1val1.st2val1', 0).value.get() == 'no' + assert api.option('od.stval2.st1val2.st1val2').value.get() == [] + assert api.option('od.stval1.st1val1.st1val1').owner.get() == owner + assert api.option('od.stval1.st1val1.st2val1', 0).owner.isdefault() + assert api.option('od.stval2.st1val2.st1val2').owner.isdefault() + +def test_masterslaves_dyndescription_param(): + val1 = StrOption('val1', '', ['val1', 'val2'], multi=True) + odval = OptionDescription('odval1', '', [val1]) + st1 = StrOption('st1', "", multi=True) + st2 = StrOption('st2', "", multi=True) + stm = MasterSlaves('st1', '', [st1, st2]) + st = DynOptionDescription('st', '', [stm], callback=return_list, callback_params=Params(ParamOption(val1))) + od = OptionDescription('od', '', [st, odval]) + od2 = OptionDescription('od', '', [od]) + cfg = Config(od2) + owner = cfg.owner.get() + assert cfg.option.make_dict() == {'od.stval1.st1val1.st2val1': [], 'od.stval2.st1val2.st2val2': [], 'od.stval2.st1val2.st1val2': [], 'od.stval1.st1val1.st1val1': [], 'od.odval1.val1': ['val1', 'val2']} + assert cfg.option('od.stval1.st1val1.st1val1').value.get() == [] + assert cfg.option('od.stval2.st1val2.st1val2').value.get() == [] + assert cfg.option('od.stval1.st1val1.st1val1').owner.get() == owners.default + assert cfg.option('od.stval2.st1val2.st1val2').owner.get() == owners.default + # + cfg.option('od.stval1.st1val1.st1val1').value.set(['yes']) + assert cfg.option.make_dict() == {'od.stval1.st1val1.st2val1': [None], 'od.stval2.st1val2.st2val2': [], 'od.stval2.st1val2.st1val2': [], 'od.stval1.st1val1.st1val1': ['yes'], 'od.odval1.val1': ['val1', 'val2']} + assert cfg.option('od.stval1.st1val1.st1val1').value.get() == ['yes'] + assert cfg.option('od.stval1.st1val1.st2val1', 0).value.get() == None + assert cfg.option('od.stval2.st1val2.st1val2').value.get() == [] + assert cfg.option('od.stval1.st1val1.st1val1').owner.get() == owner + assert cfg.option('od.stval1.st1val1.st2val1', 0).owner.get() == owners.default + assert cfg.option('od.stval2.st1val2.st1val2').owner.get() == owners.default + # + cfg.option('od.stval1.st1val1.st2val1', 0).value.set('no') + assert cfg.option('od.stval1.st1val1.st1val1').value.get() == ['yes'] + assert cfg.option('od.stval1.st1val1.st2val1', 0).value.get() == 'no' + assert cfg.option('od.stval2.st1val2.st1val2').value.get() == [] + assert cfg.option('od.stval1.st1val1.st1val1').owner.get() == owner + assert cfg.option('od.stval1.st1val1.st2val1', 0).owner.get() == owner + assert cfg.option('od.stval2.st1val2.st1val2').owner.get() == owners.default + # + cfg.option('od.stval1.st1val1.st1val1').value.pop(0) + assert cfg.option('od.stval1.st1val1.st1val1').value.get() == [] + assert cfg.option('od.stval2.st1val2.st1val2').value.get() == [] + assert cfg.option('od.stval1.st1val1.st1val1').owner.get() == owner + assert cfg.option('od.stval2.st1val2.st1val2').owner.get() == owners.default + # + cfg.option('od.stval1.st1val1.st1val1').value.set(['yes']) + cfg.option('od.stval1.st1val1.st2val1', 0).value.set('yes') + assert cfg.option('od.stval1.st1val1.st1val1').owner.get() == owner + assert cfg.option('od.stval1.st1val1.st2val1', 0).owner.get() == owner + assert cfg.option('od.stval2.st1val2.st1val2').owner.get() == owners.default + # + cfg.option('od.stval1.st1val1.st2val1', 0).value.reset() + assert cfg.option('od.stval1.st1val1.st1val1').owner.get() == owner + assert cfg.option('od.stval1.st1val1.st2val1', 0).owner.get() == owners.default + assert cfg.option('od.stval2.st1val2.st1val2').owner.get() == owners.default + # + cfg.option('od.stval1.st1val1.st1val1').value.set(['yes']) + cfg.option('od.stval1.st1val1.st2val1', 0).value.set('yes') + cfg.option('od.stval1.st1val1.st1val1').value.reset() + assert cfg.option('od.stval1.st1val1.st1val1').value.get() == [] + assert cfg.option('od.stval2.st1val2.st1val2').value.get() == [] + assert cfg.option('od.stval1.st1val1.st1val1').owner.get() == owners.default + assert cfg.option('od.stval2.st1val2.st1val2').owner.get() == owners.default + + +def test_masterslaves_default_multi_dyndescription(): + st1 = StrOption('st1', "", multi=True) + st2 = StrOption('st2', "", multi=True, default_multi='no') + stm = MasterSlaves('st1', '', [st1, st2]) + st = DynOptionDescription('st', '', [stm], callback=return_list) + od = OptionDescription('od', '', [st]) + od2 = OptionDescription('od', '', [od]) + api = Config(od2) + owner = api.owner.get() + # + assert api.option('od.stval1.st1val1.st1val1').value.get() == [] + assert api.option('od.stval2.st1val2.st1val2').value.get() == [] + assert api.option('od.stval1.st1val1.st1val1').owner.isdefault() + assert api.option('od.stval2.st1val2.st1val2').owner.isdefault() + # + api.option('od.stval1.st1val1.st1val1').value.set(['yes']) + assert api.option('od.stval1.st1val1.st1val1').value.get() == ['yes'] + assert api.option('od.stval1.st1val1.st2val1', 0).value.get() == 'no' + assert api.option('od.stval2.st1val2.st1val2').value.get() == [] + assert api.option('od.stval1.st1val1.st1val1').owner.get() == owner + assert api.option('od.stval1.st1val1.st2val1', 0).owner.isdefault() + assert api.option('od.stval2.st1val2.st1val2').owner.isdefault() + + +def _test_masterslaves(cfg): + owner = cfg.owner.get() + cfg.option('od.val1.val1').value.set(['val1', 'val2']) + cfg.option('od.val1.val2', 0).value.set('val1') + cfg.option('od.val1.val2', 1).value.set('val2') + assert cfg.option.make_dict() == {'od.stval1.st1val1.st2val1': [], 'od.stval2.st1val2.st2val2': [], 'od.stval2.st1val2.st1val2': [], 'od.stval1.st1val1.st1val1': [], 'od.val1.val1': ['val1', 'val2'], 'od.val1.val2': ['val1', 'val2']} + assert cfg.option('od.stval1.st1val1.st1val1').value.get() == [] + assert cfg.option('od.stval2.st1val2.st1val2').value.get() == [] + assert cfg.option('od.stval1.st1val1.st1val1').owner.get() == owners.default + assert cfg.option('od.stval2.st1val2.st1val2').owner.get() == owners.default + # + cfg.option('od.stval1.st1val1.st1val1').value.set(['yes']) + assert cfg.option.make_dict() == {'od.stval1.st1val1.st2val1': [None], 'od.stval2.st1val2.st2val2': [], 'od.stval2.st1val2.st1val2': [], 'od.stval1.st1val1.st1val1': ['yes'], 'od.val1.val1': ['val1', 'val2'], 'od.val1.val2': ['val1', 'val2']} + assert cfg.option('od.stval1.st1val1.st1val1').value.get() == ['yes'] + assert cfg.option('od.stval1.st1val1.st2val1', 0).value.get() == None + assert cfg.option('od.stval2.st1val2.st1val2').value.get() == [] + assert cfg.option('od.stval1.st1val1.st1val1').owner.get() == owner + assert cfg.option('od.stval1.st1val1.st2val1', 0).owner.get() == owners.default + assert cfg.option('od.stval2.st1val2.st1val2').owner.get() == owners.default + # + cfg.option('od.stval1.st1val1.st2val1', 0).value.set('no') + assert cfg.option('od.stval1.st1val1.st1val1').value.get() == ['yes'] + assert cfg.option('od.stval1.st1val1.st2val1', 0).value.get() == 'no' + assert cfg.option('od.stval2.st1val2.st1val2').value.get() == [] + assert cfg.option('od.stval1.st1val1.st1val1').owner.get() == owner + assert cfg.option('od.stval1.st1val1.st2val1', 0).owner.get() == owner + assert cfg.option('od.stval2.st1val2.st1val2').owner.get() == owners.default + # + cfg.option('od.stval1.st1val1.st1val1').value.pop(0) + assert cfg.option('od.stval1.st1val1.st1val1').value.get() == [] + assert cfg.option('od.stval2.st1val2.st1val2').value.get() == [] + assert cfg.option('od.stval1.st1val1.st1val1').owner.get() == owner + assert cfg.option('od.stval2.st1val2.st1val2').owner.get() == owners.default + # + cfg.option('od.stval1.st1val1.st1val1').value.set(['yes']) + cfg.option('od.stval1.st1val1.st2val1', 0).value.set('yes') + assert cfg.option('od.stval1.st1val1.st1val1').owner.get() == owner + assert cfg.option('od.stval1.st1val1.st2val1', 0).owner.get() == owner + assert cfg.option('od.stval2.st1val2.st1val2').owner.get() == owners.default + # + cfg.option('od.stval1.st1val1.st2val1', 0).value.reset() + assert cfg.option('od.stval1.st1val1.st1val1').owner.get() == owner + assert cfg.option('od.stval1.st1val1.st2val1', 0).owner.get() == owners.default + assert cfg.option('od.stval2.st1val2.st1val2').owner.get() == owners.default + # + cfg.option('od.stval1.st1val1.st1val1').value.set(['yes']) + cfg.option('od.stval1.st1val1.st2val1', 0).value.set('yes') + cfg.option('od.stval1.st1val1.st1val1').value.reset() + assert cfg.option('od.stval1.st1val1.st1val1').value.get() == [] + assert cfg.option('od.stval2.st1val2.st1val2').value.get() == [] + assert cfg.option('od.stval1.st1val1.st1val1').owner.get() == owners.default + assert cfg.option('od.stval2.st1val2.st1val2').owner.get() == owners.default + + +def test_masterslaves_dyndescription_param_master(): + val1 = StrOption('val1', "", multi=True) + val2 = StrOption('val2', "", multi=True) + odval = MasterSlaves('val1', '', [val1, val2]) + st1 = StrOption('st1', "", multi=True) + st2 = StrOption('st2', "", multi=True) + stm = MasterSlaves('st1', '', [st1, st2]) + st = DynOptionDescription('st', '', [stm], callback=return_list, callback_params=Params(ParamOption(val1))) + od = OptionDescription('od', '', [st, odval]) + od2 = OptionDescription('od', '', [od]) + cfg = Config(od2) + _test_masterslaves(cfg) + + +def test_masterslaves_default_multi_dyndescription(): + st1 = StrOption('st1', "", multi=True) + st2 = StrOption('st2', "", multi=True, default_multi='no') + stm = MasterSlaves('st1', '', [st1, st2]) + st = DynOptionDescription('st', '', [stm], callback=return_list) + od = OptionDescription('od', '', [st]) + od2 = OptionDescription('od', '', [od]) + api = Config(od2) + owner = api.owner.get() + # + assert api.option('od.stval1.st1val1.st1val1').value.get() == [] + assert api.option('od.stval2.st1val2.st1val2').value.get() == [] + assert api.option('od.stval1.st1val1.st1val1').owner.isdefault() + assert api.option('od.stval2.st1val2.st1val2').owner.isdefault() + # + api.option('od.stval1.st1val1.st1val1').value.set(['yes']) + assert api.option('od.stval1.st1val1.st1val1').value.get() == ['yes'] + assert api.option('od.stval1.st1val1.st2val1', 0).value.get() == 'no' + assert api.option('od.stval2.st1val2.st1val2').value.get() == [] + assert api.option('od.stval1.st1val1.st1val1').owner.get() == owner + assert api.option('od.stval1.st1val1.st2val1', 0).owner.isdefault() + assert api.option('od.stval2.st1val2.st1val2').owner.isdefault() + + +def test_masterslaves_dyndescription_param_slave(): + val1 = StrOption('val1', "", multi=True) + val2 = StrOption('val2', "", multi=True) + odval = MasterSlaves('val1', '', [val1, val2]) + st1 = StrOption('st1', "", multi=True) + st2 = StrOption('st2', "", multi=True) + stm = MasterSlaves('st1', '', [st1, st2]) + st = DynOptionDescription('st', '', [stm], callback=return_list, callback_params=Params(ParamOption(val2))) + od = OptionDescription('od', '', [st, odval]) + od2 = OptionDescription('od', '', [od]) + cfg = Config(od2) + _test_masterslaves(cfg) + + def test_masterslaves_default_multi_dyndescription(): st1 = StrOption('st1', "", multi=True) st2 = StrOption('st2', "", multi=True, default_multi='no') diff --git a/tiramisu/autolib.py b/tiramisu/autolib.py index fdff42a..4736a53 100644 --- a/tiramisu/autolib.py +++ b/tiramisu/autolib.py @@ -24,7 +24,6 @@ from typing import Any, Optional, Union, Callable, Dict, List from .error import PropertiesOptionError, ConfigError, SlaveError from .i18n import _ from .setting import undefined, ConfigBag, OptionBag, Undefined -from .option.symlinkoption import DynSymLinkOption from .storage import get_default_values_storages, get_default_settings_storages from .function import ParamValue, ParamContext, ParamIndex, ParamOption, Params # ____________________________________________________________ @@ -48,13 +47,7 @@ def manager_callback(callbk: Union[ParamOption, ParamValue], return context.duplicate(force_values=get_default_values_storages(), force_settings=get_default_settings_storages()) opt = callbk.option - if opt.issubdyn(): - 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) + path = opt.impl_getpath(context) if index is not None and opt.impl_is_master_slaves() and \ opt.impl_get_master_slaves().in_same_group(option): if opt == option: diff --git a/tiramisu/config.py b/tiramisu/config.py index 9090f06..54b8b4a 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -123,7 +123,8 @@ class SubConfig(object): for woption in option_bag.option._get_dependencies(self): option = woption() if option.impl_is_dynoptiondescription(): - for doption in option.get_syndynoptiondescriptions(option_bag): + for doption in option.get_syndynoptiondescriptions(option_bag, + remove_none=True): doption_path = doption.impl_getpath(self) doption_bag = OptionBag() doption_bag.set_option(doption, diff --git a/tiramisu/option/__init__.py b/tiramisu/option/__init__.py index 214b2e1..e22f41f 100644 --- a/tiramisu/option/__init__.py +++ b/tiramisu/option/__init__.py @@ -3,7 +3,8 @@ from .dynoptiondescription import DynOptionDescription from .syndynoptiondescription import SynDynOptionDescription from .masterslave import MasterSlaves from .baseoption import submulti -from .symlinkoption import SymLinkOption, DynSymLinkOption +from .symlinkoption import SymLinkOption +from .dynsymlinkoption import DynSymLinkOption from .option import Option, RegexpOption from .choiceoption import ChoiceOption from .booloption import BoolOption diff --git a/tiramisu/option/baseoption.py b/tiramisu/option/baseoption.py index 19f5d6a..e540cb5 100644 --- a/tiramisu/option/baseoption.py +++ b/tiramisu/option/baseoption.py @@ -28,6 +28,7 @@ from ..i18n import _ from ..setting import undefined from ..error import ConfigError, display_list from ..function import Params, ParamContext, ParamOption, ParamIndex +from .dynsymlinkoption import DynSymLinkOption STATIC_TUPLE = frozenset() @@ -450,6 +451,13 @@ class BaseOption(Base): class OnlyOption(BaseOption): __slots__ = tuple() + def impl_get_dynoption(self, + rootpath, + suffix): + return DynSymLinkOption(self, + rootpath, + suffix) + def validate_requires_arg(new_option, multi, diff --git a/tiramisu/option/dynoptiondescription.py b/tiramisu/option/dynoptiondescription.py index c15643d..d819045 100644 --- a/tiramisu/option/dynoptiondescription.py +++ b/tiramisu/option/dynoptiondescription.py @@ -71,8 +71,9 @@ class DynOptionDescription(OptionDescription): raise ConfigError(_('callback is mandatory for the dynoptiondescription "{}"' '').format(self.impl_get_display_name())) - def _impl_get_suffixes(self, - option_bag): + def impl_get_suffixes(self, + option_bag, + remove_none=False): callback, callback_params = self.impl_get_callback() values = carry_out_calculation(self, option_bag.config_bag.context, @@ -83,18 +84,30 @@ class DynOptionDescription(OptionDescription): if not isinstance(values, list): raise ValueError(_('DynOptionDescription callback for option "{}", is not a list ({})' '').format(self.impl_get_display_name(), values)) - if len(values) > len(set(values)): - raise ValueError(_('DynOptionDescription callback return not unique value')) + values_ = [] for val in values: if not isinstance(val, str) or re.match(NAME_REGEXP, val) is None: - raise ValueError(_('invalid suffix "{}" for option "{}"' - '').format(val, - self.impl_get_display_name())) - return values + if not remove_none or val is not None: + raise ValueError(_('invalid suffix "{}" for option "{}"' + '').format(val, + self.impl_get_display_name())) + else: + values_.append(val) + values = values_ + if len(values) > len(set(values)): + extra_values = values.copy() + for val in set(values): + extra_values.remove(val) + raise ValueError(_('DynOptionDescription callback return a list with multiple value ' + '"{}"''').format(extra_values)) + return values_ - def get_syndynoptiondescriptions(self, option_bag): + def get_syndynoptiondescriptions(self, + option_bag, + remove_none=False): subpath = self.impl_getpath(option_bag.config_bag.context).rsplit('.', 1)[0] - for suffix in self._impl_get_suffixes(option_bag): + for suffix in self.impl_get_suffixes(option_bag, + remove_none=remove_none): yield SynDynOptionDescription(self, subpath, suffix) diff --git a/tiramisu/option/dynsymlinkoption.py b/tiramisu/option/dynsymlinkoption.py new file mode 100644 index 0000000..86e0c8b --- /dev/null +++ b/tiramisu/option/dynsymlinkoption.py @@ -0,0 +1,83 @@ +# -*- coding: utf-8 -*- +# Copyright (C) 2018 Team tiramisu (see AUTHORS for all contributors) +# +# This program is free software: you can redistribute it and/or modify it +# under the terms of the GNU Lesser General Public License as published by the +# Free Software Foundation, either version 3 of the License, or (at your +# option) any later version. +# +# This program is distributed in the hope that it will be useful, but WITHOUT +# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS +# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more +# details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this program. If not, see . +# +# The original `Config` design model is unproudly borrowed from +# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/ +# the whole pypy projet is under MIT licence +# ____________________________________________________________ +from ..setting import undefined, OptionBag + + +class DynSymLinkOption(object): + __slots__ = ('_rootpath', + '_opt', + '_suffix') + + def __init__(self, + opt, + rootpath, + suffix): + self._opt = opt + self._rootpath = rootpath + self._suffix = suffix + + def __getattr__(self, + name): + return getattr(self._opt, name) + + def __eq__(self, left): + if not isinstance(left, DynSymLinkOption): + return False + return self._opt == left._opt and \ + self._rootpath == left._rootpath and \ + self._suffix == left._suffix + + def impl_getname(self): + return self._opt.impl_getname() + self._suffix + + def impl_get_display_name(self): + return self._opt.impl_get_display_name(dyn_name=self.impl_getname()) + + def impl_getopt(self): + return self._opt + + def impl_getsuffix(self): + return self._suffix + + def impl_getpath(self, + context): + return self._rootpath + '.' + self.impl_getname() + + def impl_validate(self, + value, + option_bag, + context=undefined, + check_error=True): + context = option_bag.config_bag.context + soption_bag = OptionBag() + soption_bag.set_option(self._opt, + self.impl_getpath(context), + option_bag.index, + option_bag.config_bag) + soption_bag.ori_option = option_bag.option + soption_bag.fromconsistency = option_bag.fromconsistency.copy() + self._opt.impl_validate(value, + soption_bag, + context=context, + check_error=check_error) + + def impl_is_dynsymlinkoption(self): + return True diff --git a/tiramisu/option/option.py b/tiramisu/option/option.py index fce60f3..f478cce 100644 --- a/tiramisu/option/option.py +++ b/tiramisu/option/option.py @@ -23,7 +23,6 @@ import warnings import weakref from .baseoption import OnlyOption, submulti, STATIC_TUPLE -from .symlinkoption import DynSymLinkOption from ..i18n import _ from ..setting import log, undefined, debug, OptionBag from ..autolib import carry_out_calculation @@ -457,7 +456,7 @@ class Option(OnlyOption): if descr._cache_consistencies is None: return # get consistencies for this option - if isinstance(option_bag.option, DynSymLinkOption): + if option_bag.option.impl_is_dynsymlinkoption(): consistencies = descr._cache_consistencies.get(option_bag.option.impl_getopt()) else: consistencies = descr._cache_consistencies.get(option_bag.option) @@ -475,12 +474,11 @@ class Option(OnlyOption): if (warnings_only and not check_error) or (not warnings_only and check_error): transitive = params.get('transitive', True) #all_cons_opts[0] is the option where func is set - if isinstance(option_bag.ori_option, DynSymLinkOption): + if option_bag.ori_option.impl_is_dynsymlinkoption(): opts = [] for opt in all_cons_opts: - opts.append(DynSymLinkOption(opt(), - option_bag.ori_option._rootpath, - option_bag.ori_option._suffix)) + opts.append(opt().impl_get_dynoption(option_bag.ori_option._rootpath, + option_bag.ori_option._suffix)) wopt = opts[0] else: opts = all_cons_opts diff --git a/tiramisu/option/optiondescription.py b/tiramisu/option/optiondescription.py index e83f635..55a5ef1 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 ConfigBag, OptionBag, groups, undefined, owners from .baseoption import BaseOption, OnlyOption -from .option import ALLOWED_CONST_LIST, DynSymLinkOption +from .option import ALLOWED_CONST_LIST from .syndynoptiondescription import SynDynOptionDescription from ..error import ConfigError, ConflictError @@ -234,12 +234,11 @@ class OptionDescriptionWalk(CacheOptionDescription): ori_index = len(rootpath) + 1 subpaths = [rootpath] + option.impl_getpath( option_bag.config_bag.context)[ori_index:].split('.')[:-1] - for suffix in dynopt._impl_get_suffixes(option_bag): + for suffix in dynopt.impl_get_suffixes(option_bag): subpath = '.'.join([subp + suffix for subp in subpaths]) if isinstance(option, OnlyOption): - yield DynSymLinkOption(option, - subpath, - suffix) + yield option.impl_get_dynoption(subpath, + suffix) else: yield SynDynOptionDescription(option, subpath, @@ -333,7 +332,7 @@ class OptionDescriptionWalk(CacheOptionDescription): subpath, None, config_bag) - for suffix in child._impl_get_suffixes(option_bag): + for suffix in child.impl_get_suffixes(option_bag): yield SynDynOptionDescription(child, subpath, suffix) @@ -360,7 +359,7 @@ class OptionDescriptionWalk(CacheOptionDescription): subconfig.cfgimpl_get_path(), None, config_bag) - for value in child._impl_get_suffixes(option_bag): + for value in child.impl_get_suffixes(option_bag): if name == cname + value: return SynDynOptionDescription(child, subconfig.cfgimpl_get_path(), @@ -375,9 +374,8 @@ class OptionDescriptionWalk(CacheOptionDescription): subpath, suffix) else: - return DynSymLinkOption(child, - subpath, - suffix) + return child.impl_get_dynoption(subpath, + suffix) class OptionDescription(OptionDescriptionWalk): diff --git a/tiramisu/option/symlinkoption.py b/tiramisu/option/symlinkoption.py index 1b50496..b3c31ad 100644 --- a/tiramisu/option/symlinkoption.py +++ b/tiramisu/option/symlinkoption.py @@ -20,7 +20,6 @@ # ____________________________________________________________ from .baseoption import OnlyOption from ..i18n import _ -from ..setting import undefined, OptionBag class SymLinkOption(OnlyOption): @@ -60,65 +59,3 @@ class SymLinkOption(OnlyOption): def get_consistencies(self): return () - - -class DynSymLinkOption(object): - __slots__ = ('_rootpath', - '_opt', - '_suffix') - - def __init__(self, - opt, - rootpath, - suffix): - self._opt = opt - self._rootpath = rootpath - self._suffix = suffix - - def __getattr__(self, - name): - return getattr(self._opt, name) - - def __eq__(self, left): - if not isinstance(left, DynSymLinkOption): - return False - return self._opt == left._opt and \ - self._rootpath == left._rootpath and \ - self._suffix == left._suffix - - def impl_getname(self): - return self._opt.impl_getname() + self._suffix - - def impl_get_display_name(self): - return self._opt.impl_get_display_name(dyn_name=self.impl_getname()) - - def impl_getopt(self): - return self._opt - - def impl_getsuffix(self): - return self._suffix - - def impl_getpath(self, - context): - return self._rootpath + '.' + self.impl_getname() - - def impl_validate(self, - value, - option_bag, - context=undefined, - check_error=True): - context = option_bag.config_bag.context - soption_bag = OptionBag() - soption_bag.set_option(self._opt, - self.impl_getpath(context), - option_bag.index, - option_bag.config_bag) - soption_bag.ori_option = option_bag.option - soption_bag.fromconsistency = option_bag.fromconsistency.copy() - self._opt.impl_validate(value, - soption_bag, - context=context, - check_error=check_error) - - def impl_is_dynsymlinkoption(self): - return True diff --git a/tiramisu/option/syndynoptiondescription.py b/tiramisu/option/syndynoptiondescription.py index 83a83d6..004b2a4 100644 --- a/tiramisu/option/syndynoptiondescription.py +++ b/tiramisu/option/syndynoptiondescription.py @@ -20,7 +20,6 @@ # ____________________________________________________________ from ..i18n import _ from ..setting import groups, undefined -from .symlinkoption import DynSymLinkOption class SynDynOptionDescription(object): @@ -81,16 +80,20 @@ class SynDynOptionDescription(object): def getmaster(self): master = self._opt.getmaster() - return DynSymLinkOption(master, - self.impl_getpath(None), - self._suffix) + return master.impl_get_dynoption(self.impl_getpath(None), + self._suffix) def getslaves(self): subpath = self.impl_getpath(None) for slave in self._opt.getslaves(): - yield DynSymLinkOption(slave, - subpath, - self._suffix) + yield slave.impl_get_dynoption(subpath, + self._suffix) + + def impl_get_display_name(self): + return self._opt.impl_get_display_name() + self._suffix + + def impl_getdoc(self): + return self._opt.impl_getdoc() + self._suffix def reset_cache(self, path, diff --git a/tiramisu/setting.py b/tiramisu/setting.py index d71775f..ba1411c 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -484,8 +484,11 @@ class Settings(object): exps, action, inverse, transitive, same_action, operator = require breaked = False for option, expected in exps: + if option.issubdyn(): + option = option.impl_get_dynoption(option_bag.option._rootpath, + option_bag.option.impl_getsuffix()) reqpath = option.impl_getpath(context) - #FIXME c'est un peu tard ! + #FIXME too later! if reqpath.startswith(option_bag.path + '.'): raise RequirementError(_("malformed requirements " "imbrication detected for option:"