From 974a178d4b1f552e42c62271585bbc9e7b4001a5 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Tue, 13 Nov 2018 22:10:01 +0100 Subject: [PATCH] simplify tiramisu/option/optiondescription.py --- test/test_config_api.py | 2 +- test/test_dereference.py | 4 +- test/test_metaconfig.py | 3 +- test/test_mixconfig.py | 4 +- test/test_option.py | 4 - tiramisu/api.py | 38 +-- tiramisu/autolib.py | 4 +- tiramisu/config.py | 141 +++++----- tiramisu/option/baseoption.py | 19 +- tiramisu/option/dynoptiondescription.py | 5 +- tiramisu/option/masterslaves.py | 7 +- tiramisu/option/option.py | 20 +- tiramisu/option/optiondescription.py | 311 ++++++++------------- tiramisu/option/symlinkoption.py | 16 +- tiramisu/option/syndynoptiondescription.py | 77 ++--- tiramisu/setting.py | 4 +- tiramisu/value.py | 3 +- 17 files changed, 302 insertions(+), 360 deletions(-) diff --git a/test/test_config_api.py b/test/test_config_api.py index 9dbf9ab..734cb86 100644 --- a/test/test_config_api.py +++ b/test/test_config_api.py @@ -50,7 +50,7 @@ def _is_same_opt(opt1, opt2): def test_od_not_list(): b = BoolOption('bool', '', multi=True) - raises(ValueError, "OptionDescription('od', '', b)") + raises(AssertionError, "OptionDescription('od', '', b)") def test_str(): diff --git a/test/test_dereference.py b/test/test_dereference.py index 8400db5..9a16f2a 100644 --- a/test/test_dereference.py +++ b/test/test_dereference.py @@ -88,7 +88,7 @@ def test_deref_option_cache(): return b = BoolOption('b', '') o = OptionDescription('od', '', [b]) - o._build_cache_option() + o._build_cache() w = weakref.ref(b) del(b) assert w() is not None @@ -101,7 +101,7 @@ def test_deref_optiondescription_cache(): return b = BoolOption('b', '') o = OptionDescription('od', '', [b]) - o._build_cache_option() + o._build_cache() w = weakref.ref(o) del(b) assert w() is not None diff --git a/test/test_metaconfig.py b/test/test_metaconfig.py index a013caa..449228a 100644 --- a/test/test_metaconfig.py +++ b/test/test_metaconfig.py @@ -342,7 +342,8 @@ def test_meta_unconsistent(): i4 = IntOption('i4', '', default=2) od1 = OptionDescription('od1', '', [i1, i2, i3, i4]) od2 = OptionDescription('od2', '', [od1]) - od3 = OptionDescription('od3', '', [od1]) + i5 = IntOption('i5', '') + od3 = OptionDescription('od3', '', [i5]) conf1 = Config(od2, session_id='conf1') conf2 = Config(od2, session_id='conf2') conf3 = Config(od2, session_id='conf3') diff --git a/test/test_mixconfig.py b/test/test_mixconfig.py index f1dcaaa..f996d6a 100644 --- a/test/test_mixconfig.py +++ b/test/test_mixconfig.py @@ -291,7 +291,9 @@ def test_mix_unconsistent(): conf1 = Config(od2, session_id='conf1') conf2 = Config(od2, session_id='conf2') conf3 = Config(od2, session_id='conf3') - conf4 = Config(od3, session_id='conf4') + i5 = IntOption('i5', '') + od4 = OptionDescription('od4', '', [i5]) + conf4 = Config(od4, session_id='conf4') mix = MixConfig(od2, [conf1, conf2]) mix.owner.set(owners.mix1) raises(TypeError, 'MixConfig(od2, "string")') diff --git a/test/test_option.py b/test/test_option.py index fbfbd13..8238ecc 100644 --- a/test/test_option.py +++ b/test/test_option.py @@ -45,7 +45,6 @@ def test_option_get_information(): raises(ValueError, "i.impl_get_information('noinfo')") assert i.impl_get_information('noinfo', 'default') == 'default' assert i.impl_get_information('doc') == description - assert i.impl_getdoc() == description def test_option_get_information_config(): @@ -61,7 +60,6 @@ def test_option_get_information_config(): raises(ValueError, "i.impl_get_information('noinfo')") assert i.impl_get_information('noinfo', 'default') == 'default' assert i.impl_get_information('doc') == description - assert i.impl_getdoc() == description def test_option_get_information_config2(): @@ -77,7 +75,6 @@ def test_option_get_information_config2(): raises(ValueError, "i.impl_get_information('noinfo')") assert i.impl_get_information('noinfo', 'default') == 'default' assert i.impl_get_information('doc') == description - assert i.impl_getdoc() == description def test_optiondescription_get_information(): @@ -89,7 +86,6 @@ def test_optiondescription_get_information(): raises(ValueError, "o.impl_get_information('noinfo')") assert o.impl_get_information('noinfo', 'default') == 'default' assert o.impl_get_information('doc') == description - assert o.impl_getdoc() == description def test_option_isoptiondescription(): diff --git a/tiramisu/api.py b/tiramisu/api.py index 8de5028..992e9b0 100644 --- a/tiramisu/api.py +++ b/tiramisu/api.py @@ -81,9 +81,9 @@ class CommonTiramisu(TiramisuHelp): def _get_option(self) -> Any: option = self._option_bag.option if option is None: - option = self._subconfig.cfgimpl_get_description().impl_getchild(self._name, - self._option_bag.config_bag, - self._subconfig.cfgimpl_get_path()) + option = self._subconfig.cfgimpl_get_description().get_child(self._name, + self._option_bag.config_bag, + self._subconfig.cfgimpl_get_path()) self._option_bag.set_option(option, self._option_bag.path, self._option_bag.index, @@ -227,9 +227,9 @@ class TiramisuOptionOption(CommonTiramisuOption): name, subconfig, option_bag): - option = subconfig.cfgimpl_get_description().impl_getchild(name, - option_bag.config_bag, - subconfig.cfgimpl_get_path()) + option = subconfig.cfgimpl_get_description().get_child(name, + option_bag.config_bag, + subconfig.cfgimpl_get_path()) if option.impl_is_optiondescription(): return _TiramisuOptionOptionDescription(name=name, subconfig=subconfig, @@ -523,9 +523,9 @@ class TiramisuOptionValue(CommonTiramisuOption): subconfig, option_bag): if subconfig is not None: - option = subconfig.cfgimpl_get_description().impl_getchild(name, - option_bag.config_bag, - subconfig.cfgimpl_get_path()) + option = subconfig.cfgimpl_get_description().get_child(name, + option_bag.config_bag, + subconfig.cfgimpl_get_path()) else: option = None types = [CommonTiramisuOption] @@ -628,9 +628,9 @@ class _TiramisuOptionDescription(_TiramisuOption): # # def get(self, name): # self._get_option() -# current_option = self._option_bag.option.impl_getchild(name, -# self._config_bag, -# self._subconfig.cfgimpl_get_path) +# current_option = self._option_bag.option.get_child(name, +# self._config_bag, +# self._subconfig.cfgimpl_get_path) # path = self._option_bag.path + '.' + name # option_bag= OptionBag() # option_bag.set_option(current_option, @@ -688,7 +688,7 @@ class _TiramisuOptionDescription(_TiramisuOption): self._config_bag) subconfig = self._subconfig.get_subconfig(name, option_bag) - for opt in option.impl_getchildren(self._config_bag): + for opt in option.get_children(self._config_bag): try: subsubconfig = self._filter(opt, subconfig) @@ -717,9 +717,9 @@ class TiramisuOption(CommonTiramisuOption): subconfig: Union[None, KernelConfig, SubConfig]=None, config_bag: Optional[ConfigBag]=None) -> None: if subconfig: - option = subconfig.cfgimpl_get_description().impl_getchild(name, - config_bag, - subconfig.cfgimpl_get_path()) + option = subconfig.cfgimpl_get_description().get_child(name, + config_bag, + subconfig.cfgimpl_get_path()) if option.impl_is_optiondescription(): return _TiramisuOptionDescription(name=name, path=path, @@ -1024,7 +1024,7 @@ class TiramisuContextOption(TiramisuContext): recursive, type_, group_type): - for opt in option.impl_getchildren(self._config_bag): + for opt in option.get_children(self._config_bag): try: subsubconfig = self._filter(opt) except PropertiesOptionError: @@ -1269,7 +1269,7 @@ class MetaConfig(TiramisuAPI): children, session_id: Union[str, None]=None, persistent: bool=False, - optiondescription: Union[OptionDescription, None]=None) -> None: + optiondescription: Optional[OptionDescription]=None) -> None: _children = [] for child in children: if isinstance(child, TiramisuAPI): @@ -1309,7 +1309,7 @@ class GroupConfig(TiramisuAPI): """GroupConfig that enables us to access the Config""" def __init__(self, children, - session_id: Union[str, None]=None) -> None: + session_id: Optional[str]=None) -> None: _children = [] for child in children: if isinstance(child, TiramisuAPI): diff --git a/tiramisu/autolib.py b/tiramisu/autolib.py index 01e6ac4..ea0ce09 100644 --- a/tiramisu/autolib.py +++ b/tiramisu/autolib.py @@ -48,8 +48,8 @@ def manager_callback(callbk: Union[ParamOption, ParamValue], force_settings=get_default_settings_storages()) opt = callbk.option if opt.issubdyn(): - opt = opt.impl_get_dynoption(option._rootpath, - option.impl_getsuffix()) + opt = opt.to_dynoption(option._rootpath, + option.impl_getsuffix()) path = opt.impl_getpath() if index is not None and opt.impl_is_master_slaves() and \ opt.impl_get_master_slaves().in_same_group(option): diff --git a/tiramisu/config.py b/tiramisu/config.py index a0ab83f..b5037c7 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -130,13 +130,13 @@ class SubConfig(object): resetted_opts, doption_bag) elif option.issubdyn(): - doption_bag = OptionBag() - doption_path = option.impl_getpath() - doption_bag.set_option(option, - doption_path, - option_bag.index, - option_bag.config_bag) - for doption in desc.get_dynoptions(doption_bag): + dynopt = option.getsubdyn() + rootpath = dynopt.impl_getpath() + subpaths = [rootpath] + option.impl_getpath()[len(rootpath) + 1:].split('.')[:-1] + for suffix in dynopt.impl_get_suffixes(option_bag.config_bag): + subpath = '.'.join([subp + suffix for subp in subpaths]) + doption = option.to_dynoption(subpath, + suffix) doption_path = doption.impl_getpath() doption_bag = OptionBag() doption_bag.set_option(doption, @@ -197,9 +197,9 @@ class SubConfig(object): path = path.split('.') for step in path[:-1]: option_bag = OptionBag() - option = self.cfgimpl_get_description().impl_getchild(step, - config_bag, - self.cfgimpl_get_path()) + option = self.cfgimpl_get_description().get_child(step, + config_bag, + self.cfgimpl_get_path()) subpath = self._get_subpath(step) option_bag.set_option(option, subpath, @@ -236,9 +236,10 @@ class SubConfig(object): raise ConfigError(_("can't assign to a SymLinkOption")) context = option_bag.config_bag.context context.cfgimpl_get_settings().validate_properties(option_bag) - self.cfgimpl_get_description().impl_validate_value(option_bag.option, - value, - self) + if option_bag.option.impl_is_master_slaves('master'): + self.cfgimpl_get_description().impl_validate_value(option_bag.option, + value, + self) return context.cfgimpl_get_values().setvalue(value, option_bag, _commit) @@ -346,7 +347,8 @@ class SubConfig(object): _subpath=None, raise_if_not_found=True, only_path=undefined, - only_option=undefined): + only_option=undefined, + with_option=False): """ convenience method for finding an option that lives only in the subtree @@ -368,9 +370,9 @@ class SubConfig(object): if only_path is not undefined: options = [only_option] else: - options = self.cfgimpl_get_description().impl_get_options(bytype, - byname, - config_bag) + options = self.cfgimpl_get_description().get_children_recursively(bytype, + byname, + config_bag) context = self.cfgimpl_get_context() for option in options: option_bag = OptionBag() @@ -390,14 +392,17 @@ class SubConfig(object): else: subconfig = self subpath = path - subconfig.cfgimpl_get_description().impl_getchild(subpath, - config_bag, - subconfig.cfgimpl_get_path()) + subconfig.cfgimpl_get_description().get_child(subpath, + config_bag, + subconfig.cfgimpl_get_path()) self.cfgimpl_get_settings().validate_properties(option_bag) except PropertiesOptionError: continue found = True - yield path + if not with_option: + yield path + else: + yield path, option self._find_return_results(found, raise_if_not_found) @@ -491,9 +496,9 @@ class SubConfig(object): else: subconfig = context subpath = path - opt = subconfig.cfgimpl_get_description().impl_getchild(subpath, - config_bag, - subconfig.cfgimpl_get_path()) + opt = subconfig.cfgimpl_get_description().get_child(subpath, + config_bag, + subconfig.cfgimpl_get_path()) soption_bag = OptionBag() soption_bag.set_option(opt, path, @@ -521,7 +526,8 @@ class SubConfig(object): #withoption can be set to None below ! if withoption is None: - for opt in self.cfgimpl_get_description().impl_getchildren(config_bag, context): + for opt in self.cfgimpl_get_description().get_children(config_bag, + context): name = opt.impl_getname() path = self._get_subpath(name) soption_bag = OptionBag() @@ -618,9 +624,9 @@ class _CommonConfig(SubConfig): def _impl_build_all_caches(self): descr = self.cfgimpl_get_description() if not descr.impl_already_build_caches(): - descr._build_cache_option() - descr._build_cache(self) - descr.impl_build_force_store_values(self) + descr._build_cache() + config_bag = ConfigBag(context=self) + descr.impl_build_force_store_values(config_bag) def cfgimpl_get_path(self, dyn=True): return None @@ -849,9 +855,9 @@ class KernelGroupConfig(_CommonConfig): try: subconfig, name = child.cfgimpl_get_home_by_path(path, cconfig_bag) - option = subconfig.cfgimpl_get_description().impl_getchild(name, - cconfig_bag, - child.cfgimpl_get_path()) + option = subconfig.cfgimpl_get_description().get_child(name, + cconfig_bag, + child.cfgimpl_get_path()) option_bag = OptionBag() option_bag.set_option(option, path, @@ -885,19 +891,18 @@ class KernelGroupConfig(_CommonConfig): _sub=False): """Find first not in current KernelGroupConfig, but in each children """ - #if KernelMetaConfig, all children have same OptionDescription in context - #so search only one time the option for all children + # if KernelMetaConfig, all children have same OptionDescription in + # context so search only one time the option for all children if bypath is undefined and byname is not None and \ isinstance(self, KernelMixConfig): - bypath = next(self.find(bytype=None, - byvalue=undefined, - byname=byname, - config_bag=config_bag, - raise_if_not_found=raise_if_not_found)) + bypath, byoption = next(self.find(bytype=None, + byvalue=undefined, + byname=byname, + config_bag=config_bag, + raise_if_not_found=raise_if_not_found, + with_option=True)) byname = None - byoption = self.cfgimpl_get_description().impl_get_opt_by_path(bypath, - config_bag) ret = [] for child in self._impl_children: @@ -939,9 +944,9 @@ class KernelGroupConfig(_CommonConfig): config_bag.remove_validation() subconfig, name = child.cfgimpl_get_home_by_path(path, config_bag) - option = subconfig.cfgimpl_get_description().impl_getchild(name, - config_bag, - subconfig.cfgimpl_get_path()) + option = subconfig.cfgimpl_get_description().get_child(name, + config_bag, + subconfig.cfgimpl_get_path()) option_bag = OptionBag() option_bag.set_option(option, path, @@ -1024,9 +1029,9 @@ class KernelMixConfig(KernelGroupConfig): ret = [] subconfig, name = self.cfgimpl_get_home_by_path(path, config_bag) - option = subconfig.cfgimpl_get_description().impl_getchild(name, - config_bag, - self.cfgimpl_get_path()) + option = subconfig.cfgimpl_get_description().get_child(name, + config_bag, + self.cfgimpl_get_path()) option_bag = OptionBag() option_bag.set_option(option, path, @@ -1040,17 +1045,17 @@ class KernelMixConfig(KernelGroupConfig): cconfig_bag = config_bag.copy() cconfig_bag.context = child try: + subconfig2, name = child.cfgimpl_get_home_by_path(path, + cconfig_bag) if self.impl_type == 'meta': moption_bag = option_bag del moption_bag.properties del moption_bag.permissives moption_bag.config_bag = cconfig_bag else: - subconfig, name = child.cfgimpl_get_home_by_path(path, - cconfig_bag) - option = subconfig.cfgimpl_get_description().impl_getchild(name, - cconfig_bag, - child.cfgimpl_get_path()) + option = subconfig2.cfgimpl_get_description().get_child(name, + cconfig_bag, + child.cfgimpl_get_path()) moption_bag = OptionBag() moption_bag.set_option(option, path, @@ -1060,8 +1065,8 @@ class KernelMixConfig(KernelGroupConfig): if not child.cfgimpl_get_values()._p_.hasvalue(path): child_value = undefined else: - child_value = child.getattr(name, - moption_bag) + child_value = subconfig2.getattr(name, + moption_bag) if force_default or (force_default_if_same and value == child_value): child.cfgimpl_get_values().reset(moption_bag, _commit=False) @@ -1070,9 +1075,9 @@ class KernelMixConfig(KernelGroupConfig): child_value = child.getattr(name, moption_bag) if value != child_value: - child.setattr(child_value, - moption_bag, - _commit=False) + subconfig2.setattr(child_value, + moption_bag, + _commit=False) except PropertiesOptionError as err: ret.append(PropertiesOptionError(err._option_bag, err.proptype, @@ -1089,9 +1094,9 @@ class KernelMixConfig(KernelGroupConfig): del option_bag.properties del option_bag.permissives option_bag.config_bag = config_bag - self.setattr(value, - option_bag, - _commit=False) + subconfig.setattr(value, + option_bag, + _commit=False) except (PropertiesOptionError, ValueError, SlaveError) as err: ret.append(err) return ret @@ -1106,9 +1111,9 @@ class KernelMixConfig(KernelGroupConfig): if self.impl_type == 'meta': subconfig, name = self.cfgimpl_get_home_by_path(path, config_bag) - option = subconfig.cfgimpl_get_description().impl_getchild(name, - config_bag, - subconfig.cfgimpl_get_path()) + option = subconfig.cfgimpl_get_description().get_child(name, + config_bag, + subconfig.cfgimpl_get_path()) option_bag = OptionBag() option_bag.set_option(option, path, @@ -1118,9 +1123,9 @@ class KernelMixConfig(KernelGroupConfig): try: subconfig, name = self.cfgimpl_get_home_by_path(path, config_bag) - option = subconfig.cfgimpl_get_description().impl_getchild(name, - config_bag, - subconfig.cfgimpl_get_path()) + option = subconfig.cfgimpl_get_description().get_child(name, + config_bag, + subconfig.cfgimpl_get_path()) option_bag = OptionBag() option_bag.set_option(option, path, @@ -1137,9 +1142,9 @@ class KernelMixConfig(KernelGroupConfig): else: subconfig, name = child.cfgimpl_get_home_by_path(path, rconfig_bag) - option = subconfig.cfgimpl_get_description().impl_getchild(name, - rconfig_bag, - child.cfgimpl_get_path()) + option = subconfig.cfgimpl_get_description().get_child(name, + rconfig_bag, + child.cfgimpl_get_path()) moption_bag = OptionBag() moption_bag.set_option(option, path, diff --git a/tiramisu/option/baseoption.py b/tiramisu/option/baseoption.py index 7d989ee..cfb3c3a 100644 --- a/tiramisu/option/baseoption.py +++ b/tiramisu/option/baseoption.py @@ -23,12 +23,15 @@ from types import FunctionType import weakref from inspect import signature from itertools import chain +from typing import Union + from ..i18n import _ from ..setting import undefined from ..error import ConfigError, display_list from ..function import Params, ParamContext, ParamOption, ParamIndex from .dynsymlinkoption import DynSymLinkOption +from .syndynoptiondescription import SynDynOptionDescription STATIC_TUPLE = frozenset() @@ -425,7 +428,7 @@ class BaseOption(Base): def impl_get_display_name(self, dyn_name=None): - name = self.impl_getdoc() + name = self.impl_get_information('doc') if name is None or name == '': if dyn_name is not None: name = dyn_name @@ -446,13 +449,13 @@ class BaseOption(Base): def impl_is_symlinkoption(self): return False - -class OnlyOption(BaseOption): - __slots__ = tuple() - - def impl_get_dynoption(self, - rootpath, - suffix): + def to_dynoption(self, + rootpath: str, + suffix: str) -> Union[SynDynOptionDescription, DynSymLinkOption]: + if self.impl_is_optiondescription(): + return SynDynOptionDescription(self, + rootpath, + suffix) return DynSymLinkOption(self, rootpath, suffix) diff --git a/tiramisu/option/dynoptiondescription.py b/tiramisu/option/dynoptiondescription.py index 1e70beb..e08da95 100644 --- a/tiramisu/option/dynoptiondescription.py +++ b/tiramisu/option/dynoptiondescription.py @@ -54,7 +54,7 @@ class DynOptionDescription(OptionDescription): if child.impl_get_group_type() != groups.master: raise ConfigError(_('cannot set optiondescription in a ' 'dynoptiondescription')) - for chld in child.impl_getchildren(config_bag=undefined): + for chld in child.get_children(config_bag=undefined): chld._setsubdyn(self) if child.impl_is_symlinkoption(): raise ConfigError(_('cannot set symlinkoption in a ' @@ -111,3 +111,6 @@ class DynOptionDescription(OptionDescription): yield SynDynOptionDescription(self, subpath, suffix) + + def impl_is_dynoptiondescription(self): + return True diff --git a/tiramisu/option/masterslaves.py b/tiramisu/option/masterslaves.py index fd13297..7a51ebf 100644 --- a/tiramisu/option/masterslaves.py +++ b/tiramisu/option/masterslaves.py @@ -219,10 +219,9 @@ class MasterSlaves(OptionDescription): option, value, context): - if option.impl_is_master_slaves('master') and isinstance(value, list): - if len(value) < context._impl_length: - raise SlaveError(_('cannot reduce length of the master "{}"' - '').format(option.impl_get_display_name())) + if isinstance(value, list) and len(value) < context._impl_length: + raise SlaveError(_('cannot reduce length of the master "{}"' + '').format(option.impl_get_display_name())) def impl_is_master_slaves(self, *args, **kwargs): return True diff --git a/tiramisu/option/option.py b/tiramisu/option/option.py index 11305f2..a28d553 100644 --- a/tiramisu/option/option.py +++ b/tiramisu/option/option.py @@ -23,7 +23,7 @@ import warnings import weakref from typing import Any, List, Callable, Optional -from .baseoption import OnlyOption, submulti, STATIC_TUPLE +from .baseoption import BaseOption, submulti, STATIC_TUPLE from ..i18n import _ from ..setting import log, undefined, OptionBag from ..autolib import carry_out_calculation @@ -33,7 +33,7 @@ from ..function import Params, ParamValue ALLOWED_CONST_LIST = ['_cons_not_equal'] -class Option(OnlyOption): +class Option(BaseOption): """ Abstract base class for configuration option's. @@ -179,10 +179,6 @@ class Option(OnlyOption): def impl_is_dynsymlinkoption(self): return False - def impl_getdoc(self): - "accesses the Option's doc" - return self.impl_get_information('doc') - def impl_getdefault(self): "accessing the default value" is_multi = self.impl_is_multi() @@ -472,7 +468,7 @@ class Option(OnlyOption): def has_consistencies(self, context): descr = context.cfgimpl_get_description() - if descr._cache_consistencies is None: + if getattr(descr, '_cache_consistencies', None) is None: return False return self in descr._cache_consistencies @@ -484,7 +480,7 @@ class Option(OnlyOption): if option_bag.config_bag is not undefined: descr = option_bag.config_bag.context.cfgimpl_get_description() # no consistency found at all - if descr._cache_consistencies is None: + if getattr(descr, '_cache_consistencies', None) is None: return # get consistencies for this option consistencies = descr._cache_consistencies.get(option_bag.option) @@ -515,8 +511,8 @@ class Option(OnlyOption): if option_bag.ori_option.impl_is_dynsymlinkoption(): opts = [] for opt in all_cons_opts: - opts.append(opt().impl_get_dynoption(option_bag.ori_option._rootpath, - option_bag.ori_option._suffix)) + opts.append(opt().to_dynoption(option_bag.ori_option._rootpath, + option_bag.ori_option._suffix)) wopt = opts[0] else: opts = all_cons_opts @@ -571,12 +567,12 @@ class Option(OnlyOption): opt._has_dependency = True def launch_consistency(self, - current_opt: OnlyOption, + current_opt: BaseOption, func: Callable, cons_id: int, option_bag: OptionBag, value: Any, - opts: List[OnlyOption], + opts: List[BaseOption], warnings_only: bool, transitive: bool): """Launch consistency now diff --git a/tiramisu/option/optiondescription.py b/tiramisu/option/optiondescription.py index 64a55ec..ebc7867 100644 --- a/tiramisu/option/optiondescription.py +++ b/tiramisu/option/optiondescription.py @@ -19,72 +19,78 @@ # the whole pypy projet is under MIT licence # ____________________________________________________________ from copy import copy +from typing import Optional, Iterator, Union, List from ..i18n import _ -from ..setting import ConfigBag, OptionBag, groups, undefined, owners -from .baseoption import BaseOption, OnlyOption +from ..setting import ConfigBag, OptionBag, groups, undefined, owners, Undefined +from .baseoption import BaseOption from .option import ALLOWED_CONST_LIST from .syndynoptiondescription import SynDynOptionDescription from ..error import ConfigError, ConflictError class CacheOptionDescription(BaseOption): - __slots__ = ('_cache_consistencies', '_cache_force_store_values') + __slots__ = ('_cache_consistencies', + '_cache_force_store_values') + + def impl_already_build_caches(self) -> bool: + return self.impl_is_readonly() def _build_cache(self, - config, path='', _consistencies=None, _consistencies_id=0, + currpath: List[str]=None, cache_option=None, - force_store_values=None): - """validate duplicate option and set option has readonly option + force_store_values=None) -> None: + """validate options and set option has readonly option """ - # cache_option is None only when we start to build cache - if cache_option is None: - if self.impl_is_readonly(): - raise ConfigError(_('option description seems to be part of an other ' - 'config')) + # _consistencies is None only when we start to build cache + if _consistencies is None: init = True _consistencies = {} - cache_option = [] + if __debug__: + cache_option = [] force_store_values = [] + currpath = [] else: init = False - for option in self.impl_getchildren(config_bag=undefined, - dyn=False): - cache_option.append(option) - if path == '': - subpath = option.impl_getname() - else: - subpath = path + '.' + option.impl_getname() + if self.impl_is_readonly(): + # cache already set + raise ConfigError(_('option description seems to be part of an other ' + 'config')) + for option in self.get_children(config_bag=undefined, + dyn=False): + if __debug__: + cache_option.append(option) + sub_currpath = currpath + [option.impl_getname()] + subpath = '.'.join(sub_currpath) if isinstance(option, OptionDescription): - option._set_readonly() - option._build_cache(config, - subpath, + option._build_cache(subpath, _consistencies, _consistencies_id, + sub_currpath, cache_option, force_store_values) else: - option._set_readonly() is_multi = option.impl_is_multi() if not option.impl_is_symlinkoption(): properties = option.impl_getproperties() if 'force_store_value' in properties: - if option.impl_is_master_slaves('slave'): - # problem with index - raise ConfigError(_('the slave "{0}" cannot have ' - '"force_store_value" property').format( - option.impl_get_display_name())) - if option.issubdyn(): - raise ConfigError(_('the dynoption "{0}" cannot have ' - '"force_store_value" property').format( - option.impl_get_display_name())) + if __debug__: + if option.impl_is_master_slaves('slave'): + # problem with index + raise ConfigError(_('the slave "{0}" cannot have ' + '"force_store_value" property').format( + option.impl_get_display_name())) + if option.issubdyn(): + raise ConfigError(_('the dynoption "{0}" cannot have ' + '"force_store_value" property').format( + option.impl_get_display_name())) force_store_values.append((subpath, option)) - if 'force_default_on_freeze' in properties and \ + if __debug__ and 'force_default_on_freeze' in properties and \ 'frozen' not in properties and \ option.impl_is_master_slaves('master'): raise ConfigError(_('a master ({0}) cannot have ' @@ -93,15 +99,14 @@ class CacheOptionDescription(BaseOption): for cons_id, func, all_cons_opts, params in option.get_consistencies(): option._valid_consistencies(all_cons_opts[1:], init=False) if func not in ALLOWED_CONST_LIST and is_multi: - is_masterslaves = option.impl_is_master_slaves() - if not is_masterslaves: + if __debug__ and not option.impl_is_master_slaves(): raise ConfigError(_('malformed consistency option "{0}" ' 'must be a masterslaves').format( option.impl_getname())) masterslaves = option.impl_get_master_slaves() for weak_opt in all_cons_opts: opt = weak_opt() - if func not in ALLOWED_CONST_LIST and is_multi: + if __debug__ and func not in ALLOWED_CONST_LIST and is_multi: if not opt.impl_is_master_slaves(): raise ConfigError(_('malformed consistency option "{0}" ' 'must not be a multi for "{1}"').format( @@ -119,10 +124,11 @@ class CacheOptionDescription(BaseOption): # if context is set to callback, must be reset each time a value change if hasattr(option, '_has_calc_context'): self._add_dependency(option) - is_slave = None - if is_multi: - all_requires = option.impl_getrequires() - if all_requires != tuple(): + + if __debug__: + is_slave = None + if is_multi: + all_requires = option.impl_getrequires() for requires in all_requires: for require in requires: #if option in require is a multi: @@ -144,8 +150,11 @@ class CacheOptionDescription(BaseOption): raise ValueError(_('malformed requirements option "{0}" ' 'must not be a multi for "{1}"').format( require_opt.impl_getname(), option.impl_getname())) + if not hasattr(option, '_path'): + option._path = subpath + option._set_readonly() if init: - if len(cache_option) != len(set(cache_option)): + if __debug__ and len(cache_option) != len(set(cache_option)): for idx in range(1, len(cache_option) + 1): opt = cache_option.pop(0) if opt in cache_option: @@ -154,7 +163,7 @@ class CacheOptionDescription(BaseOption): self._cache_consistencies = {} for weak_opt, cons in _consistencies.items(): opt = weak_opt() - if opt not in cache_option: + if __debug__ and opt not in cache_option: raise ConfigError(_('consistency with option {0} ' 'which is not in Config').format( opt.impl_getname())) @@ -162,69 +171,43 @@ class CacheOptionDescription(BaseOption): self._cache_force_store_values = force_store_values self._set_readonly() - def impl_already_build_caches(self): - if hasattr(self, '_cache_consistencies'): - return True - return False - def impl_build_force_store_values(self, - context): - value_setted = False - values = context.cfgimpl_get_values() + config_bag: ConfigBag) -> None: + commit = False + if not hasattr(self, '_cache_force_store_values'): + raise ConfigError(_('option description seems to be part of an other ' + 'config')) + values = config_bag.context.cfgimpl_get_values() for subpath, option in self._cache_force_store_values: if not values._p_.hasvalue(subpath): - config_bag = ConfigBag(context=context) option_bag = OptionBag() option_bag.set_option(option, subpath, None, config_bag) option_bag.properties = frozenset() - value = values.getvalue(option_bag) - value_setted = True values._p_.setvalue(subpath, - value, + values.getvalue(option_bag), owners.forced, None, False) + commit = True - if value_setted: + if commit: values._p_.commit() - def _build_cache_option(self, - _currpath=None): - - if self.impl_is_readonly() or \ - (_currpath is None and getattr(self, '_cache_consistencies', None) is not None): - # cache already set - return - if _currpath is None: - save = True - _currpath = [] - else: - save = False - for option in self.impl_getchildren(config_bag=undefined, - dyn=False): - attr = option.impl_getname() - path = str('.'.join(_currpath + [attr])) - option._path = path - if option.impl_is_optiondescription(): - _currpath.append(attr) - option._build_cache_option(_currpath) - _currpath.pop() - if save and not hasattr(self, '_cache_consistencies'): - self._cache_consistencies = None - class OptionDescriptionWalk(CacheOptionDescription): __slots__ = ('_children',) - def impl_getchild(self, - name, - config_bag, - subpath): + def get_child(self, + name: str, + config_bag: ConfigBag, + subpath: str) -> Union[BaseOption, SynDynOptionDescription]: + # if not dyn if name in self._children[0]: return self._children[1][self._children[0].index(name)] + # if dyn for child in self._children[1]: if child.impl_is_dynoptiondescription(): cname = child.impl_getname() @@ -238,17 +221,16 @@ class OptionDescriptionWalk(CacheOptionDescription): 'in optiondescription "{1}"' '').format(name, self.impl_getname())) - def impl_getchildren(self, - config_bag, - dyn=True): - subpath = None + def get_children(self, + config_bag: Union[ConfigBag, Undefined], + dyn: bool=True) -> Iterator[Union[BaseOption, SynDynOptionDescription]]: + if not dyn or config_bag is undefined or \ + config_bag.context.cfgimpl_get_description() == self: + subpath = '' + else: + subpath = self.impl_getpath() for child in self._children[1]: if dyn and child.impl_is_dynoptiondescription(): - if subpath is None: - if config_bag.context.cfgimpl_get_description() == self: - subpath = '' - else: - subpath = self.impl_getpath() for suffix in child.impl_get_suffixes(config_bag): yield SynDynOptionDescription(child, subpath, @@ -256,69 +238,22 @@ class OptionDescriptionWalk(CacheOptionDescription): else: yield child - def impl_get_opt_by_path(self, - path, - config_bag): - opt = self - subpath = None - for step in path.split('.'): - opt = opt.impl_getchild(step, - config_bag, - subpath) - if subpath is None: - subpath = step - else: - subpath += '.' + step - return opt - - def impl_get_options(self, - bytype, - byname, - config_bag, - self_opt=None): + def get_children_recursively(self, + bytype: Optional[BaseOption], + byname: Optional[str], + config_bag: ConfigBag, + self_opt: BaseOption=None) -> Iterator[Union[BaseOption, SynDynOptionDescription]]: if self_opt is None: self_opt = self - def _filter_by_name(option): - return byname is None or option.impl_getname() == byname - - for option in self_opt.impl_getchildren(config_bag): + for option in self_opt.get_children(config_bag): if option.impl_is_optiondescription(): - for subopt in option.impl_get_options(bytype, - byname, - config_bag): + for subopt in option.get_children_recursively(bytype, + byname, + config_bag): yield subopt - else: - if bytype is not None: - if isinstance(option, bytype) and \ - _filter_by_name(option): - yield option - elif _filter_by_name(option): - yield option - - def get_dynoptions(self, - option_bag): - option = option_bag.option - dynopt = option.getsubdyn() - rootpath = dynopt.impl_getpath() - ori_index = len(rootpath) + 1 - subpaths = [rootpath] + option.impl_getpath()[ori_index:].split('.')[:-1] - for suffix in dynopt.impl_get_suffixes(option_bag.config_bag): - subpath = '.'.join([subp + suffix for subp in subpaths]) - yield self.impl_get_dynchild(option, - suffix, - subpath) - - def impl_get_dynchild(self, - child, - suffix, - subpath): - if isinstance(child, OptionDescription): - return SynDynOptionDescription(child, - subpath, - suffix) - else: - return child.impl_get_dynoption(subpath, - suffix) + elif (byname is None or option.impl_getname() == byname) and \ + (bytype is None or isinstance(option, bytype)): + yield option class OptionDescription(OptionDescriptionWalk): @@ -328,68 +263,65 @@ class OptionDescription(OptionDescriptionWalk): __slots__ = ('_group_type',) def __init__(self, - name, - doc, - children, + name: str, + doc: str, + children: List[BaseOption], requires=None, - properties=None): + properties=None) -> None: """ :param children: a list of options (including optiondescriptions) """ - if not isinstance(children, list): - raise ValueError(_('children in optiondescription "{}" must be a list').format(name)) + assert isinstance(children, list), _('children in optiondescription "{}" ' + 'must be a list').format(name) super().__init__(name, doc=doc, requires=requires, properties=properties) child_names = [] - dynopt_names = [] + if __debug__: + dynopt_names = [] for child in children: name = child.impl_getname() child_names.append(name) - if child.impl_is_dynoptiondescription(): + if __debug__ and child.impl_is_dynoptiondescription(): dynopt_names.append(name) + # before sorting children_ = (tuple(child_names), tuple(children)) - # better performance like this - child_names.sort() - old = None - for child in child_names: - if child == old: - raise ConflictError(_('duplicate option name: ' - '"{0}"').format(child)) - if dynopt_names: - for dynopt in dynopt_names: - if child != dynopt and child.startswith(dynopt): - raise ConflictError(_('the option\'s name "{}" start as ' - 'the dynoptiondescription\'s name "{}"').format(child, dynopt)) - old = child + if __debug__: + # better performance like this + child_names.sort() + old = None + for child in child_names: + if child == old: + raise ConflictError(_('duplicate option name: ' + '"{0}"').format(child)) + if dynopt_names: + for dynopt in dynopt_names: + if child != dynopt and child.startswith(dynopt): + raise ConflictError(_('the option\'s name "{}" start as ' + 'the dynoptiondescription\'s name "{}"').format(child, dynopt)) + old = child self._children = children_ - #self._cache_consistencies = None # the group_type is useful for filtering OptionDescriptions in a config self._group_type = groups.default - def impl_is_optiondescription(self): - return self.__class__.__name__ in ['OptionDescription', - 'DynOptionDescription', - 'SynDynOptionDescription', - 'MasterSlaves'] + def impl_is_optiondescription(self) -> bool: + return True - def impl_is_dynoptiondescription(self): - return self.__class__.__name__ in ['DynOptionDescription', - 'SynDynOptionDescription'] - - def impl_is_master_slaves(self, *args, **kwargs): + def impl_is_dynoptiondescription(self) -> bool: return False - def impl_getdoc(self): - return self.impl_get_information('doc') + def impl_is_master_slaves(self, + *args, + **kwargs) -> bool: + return False # ____________________________________________________________ def impl_set_group_type(self, - group_type): + group_type: groups.GroupType) -> None: """sets a given group object to an OptionDescription :param group_type: an instance of `GroupType` or `MasterGroupType` @@ -406,10 +338,5 @@ class OptionDescription(OptionDescriptionWalk): raise ConfigError('please use MasterSlaves object instead of OptionDescription') self._group_type = group_type - def impl_get_group_type(self): + def impl_get_group_type(self) -> groups.GroupType: return self._group_type - - def impl_validate_value(self, - *args, - **kwargs): - pass diff --git a/tiramisu/option/symlinkoption.py b/tiramisu/option/symlinkoption.py index 8c13dc9..869b64d 100644 --- a/tiramisu/option/symlinkoption.py +++ b/tiramisu/option/symlinkoption.py @@ -18,21 +18,21 @@ # the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/ # the whole pypy projet is under MIT licence # ____________________________________________________________ -from .baseoption import OnlyOption +from .baseoption import BaseOption from ..i18n import _ -class SymLinkOption(OnlyOption): +class SymLinkOption(BaseOption): __slots__ = ('_opt',) def __init__(self, - name, - opt): - if not isinstance(opt, OnlyOption) or \ + name: str, + opt: BaseOption) -> None: + if not isinstance(opt, BaseOption) or \ + opt.impl_is_optiondescription() or \ opt.impl_is_symlinkoption(): - raise ValueError(_('malformed symlinkoption ' - 'must be an option ' - 'for symlink {0}').format(name)) + raise ValueError(_('malformed symlinkoption must be an option for symlink {0}' + '').format(name)) _setattr = object.__setattr__ _setattr(self, '_name', name) _setattr(self, '_opt', opt) diff --git a/tiramisu/option/syndynoptiondescription.py b/tiramisu/option/syndynoptiondescription.py index a74f00d..660a89e 100644 --- a/tiramisu/option/syndynoptiondescription.py +++ b/tiramisu/option/syndynoptiondescription.py @@ -18,8 +18,12 @@ # the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/ # the whole pypy projet is under MIT licence # ____________________________________________________________ +from typing import Optional, Iterator, Union + + from ..i18n import _ -from ..setting import groups, undefined +from ..setting import ConfigBag, groups, undefined +#from .baseoption import BaseOption class SynDynOptionDescription(object): @@ -41,20 +45,21 @@ class SynDynOptionDescription(object): def impl_getopt(self): return self._opt - def impl_getchild(self, - name, - config_bag, - subpath): - try: - if name.endswith(self._suffix): - oname = name[:-len(self._suffix)] + def get_child(self, + name: str, + config_bag: ConfigBag, + subpath: str): + #FIXME -> Union[BaseOption, SynDynOptionDescription]: + if name.endswith(self._suffix): + oname = name[:-len(self._suffix)] + try: child = self._children[1][self._children[0].index(oname)] - return self.impl_get_dynchild(child, - self._suffix, - subpath) - except ValueError: - # when oname not in self._children - pass + except ValueError: + # when oname not in self._children + pass + else: + return child.to_dynoption(subpath, + self._suffix) raise AttributeError(_('unknown option "{0}" ' 'in syndynoptiondescription "{1}"' '').format(name, self.impl_getname())) @@ -62,25 +67,29 @@ class SynDynOptionDescription(object): def impl_getname(self): return self._opt.impl_getname() + self._suffix - def impl_getchildren(self, - config_bag, - dyn=True): + def impl_is_dynoptiondescription(self): + return True + + def get_children(self, + config_bag, + dyn=True): children = [] subpath = self.impl_getpath() - for child in self._opt.impl_getchildren(config_bag): - yield self._opt.impl_get_dynchild(child, - self._suffix, - subpath) - - def impl_get_options(self, - bytype, - byname, - config_bag): - return self._opt.impl_get_options(bytype, - byname, - config_bag, - self) + for child in self._opt.get_children(config_bag): + yield child.to_dynoption(subpath, + self._suffix) + def get_children_recursively(self, + bytype, # FIXME : Optional[BaseOption], + byname: Optional[str], + config_bag: ConfigBag, + self_opt=None): # FIXME : BaseOption=None) + # FIXME -> Iterator[Union[BaseOption, SynDynOptionDescription]]: + return self._opt.get_children_recursively(bytype, + byname, + config_bag, + self) + def impl_getpath(self): subpath = self._subpath if subpath != '': @@ -89,14 +98,14 @@ class SynDynOptionDescription(object): def getmaster(self): master = self._opt.getmaster() - return master.impl_get_dynoption(self.impl_getpath(), - self._suffix) + return master.to_dynoption(self.impl_getpath(), + self._suffix) def getslaves(self): subpath = self.impl_getpath() for slave in self._opt.getslaves(): - yield slave.impl_get_dynoption(subpath, - self._suffix) + yield slave.to_dynoption(subpath, + self._suffix) def impl_get_display_name(self): return self._opt.impl_get_display_name() + self._suffix diff --git a/tiramisu/setting.py b/tiramisu/setting.py index 6e1f3a7..a4295a8 100644 --- a/tiramisu/setting.py +++ b/tiramisu/setting.py @@ -484,8 +484,8 @@ class Settings(object): breaked = False for option, expected in exps: if option.issubdyn(): - option = option.impl_get_dynoption(option_bag.option._rootpath, - option_bag.option.impl_getsuffix()) + option = option.to_dynoption(option_bag.option._rootpath, + option_bag.option.impl_getsuffix()) reqpath = option.impl_getpath() #FIXME too later! if reqpath.startswith(option_bag.path + '.'): diff --git a/tiramisu/value.py b/tiramisu/value.py index caec421..263d6ee 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -524,7 +524,8 @@ class Values(object): subconfig, od_config_bag): settings = context.cfgimpl_get_settings() - for option in description.impl_getchildren(config_bag, context): + for option in description.get_children(config_bag, + context): name = option.impl_getname() path = '.'.join(currpath + [name])