From 290f687f6c296b3d96335b904791db7e68eedc92 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Sun, 7 Oct 2018 10:55:52 +0200 Subject: [PATCH] help in API became usable --- test/test_config.py | 6 + test/test_config_api.py | 51 +- test/test_dyn_optiondescription.py | 2 +- test/test_metaconfig.py | 2 +- test/test_option_setting.py | 2 +- tiramisu/__init__.py | 3 +- tiramisu/api.py | 1248 ++++++++++++++------------ tiramisu/config.py | 3 + tiramisu/option/optiondescription.py | 2 - tiramisu/storage/dictionary/value.py | 6 + tiramisu/storage/sqlite3/value.py | 8 + tiramisu/value.py | 3 + 12 files changed, 716 insertions(+), 620 deletions(-) diff --git a/test/test_config.py b/test/test_config.py index 72908b2..d67e8c4 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -136,14 +136,17 @@ def test_information_config(): config = Config(descr) string = 'some informations' # + assert list(config.information.list()) == [] config.information.set('info', string) assert config.information.get('info') == string + assert list(config.information.list()) == ['info'] # raises(ValueError, "config.information.get('noinfo')") assert config.information.get('noinfo', 'default') == 'default' config.information.reset('info') raises(ValueError, "config.information.get('info')") raises(ValueError, "config.information.reset('noinfo')") + assert list(config.information.list()) == [] def test_information_option(): @@ -151,14 +154,17 @@ def test_information_option(): config = Config(descr) string = 'some informations' # + list(config.option('gc.name').information.list()) == [] config.option('gc.name').information.set('info', string) assert config.option('gc.name').information.get('info') == string + list(config.option('gc.name').information.list()) == ['info'] # raises(ValueError, "config.option('gc.name').information.get('noinfo')") assert config.option('gc.name').information.get('noinfo', 'default') == 'default' config.option('gc.name').information.reset('info') raises(ValueError, "config.option('gc.name').information.get('info')") raises(ValueError, "config.option('gc.name').information.reset('noinfo')") + list(config.option('gc.name').information.list()) == [] # assert config.option('wantref').information.get('info') == 'default value' config.option('wantref').information.set('info', 'default value') diff --git a/test/test_config_api.py b/test/test_config_api.py index ba57e29..bbf622d 100644 --- a/test/test_config_api.py +++ b/test/test_config_api.py @@ -149,14 +149,14 @@ def test_find_in_config(): conf = Config(descr) conf.property.read_only() conf.permissive.set(frozenset(['hidden'])) - ret = conf.option.find('dummy') + ret = list(conf.option.find('dummy')) assert len(ret) == 1 _is_same_opt(ret[0].option.get(), conf.option('gc.dummy').option.get()) # ret = conf.option.find('dummy', first=True).option.get() _is_same_opt(ret, conf.option('gc.dummy').option.get()) # - ret = conf.option.find('float') + ret = list(conf.option.find('float')) assert len(ret) == 2 _is_same_opt(ret[0].option.get(), conf.option('gc.float').option.get()) _is_same_opt(ret[1].option.get(), conf.option('float').option.get()) @@ -177,48 +177,49 @@ def test_find_in_config(): #_is_same_opt(ret[0], conf.unwrap_from_path('gc.name')) #_is_same_opt(conf.find_first(byvalue='ref'), conf.unwrap_from_path('gc.name')) # - ret = conf.option.find('prop') + ret = list(conf.option.find('prop')) assert len(ret) == 1 _is_same_opt(ret[0].option.get(), conf.option('gc.prop').option.get()) # - ret = conf.option.find('prop', value=None) - ret = conf.option.find('prop') + ret = list(conf.option.find('prop', value=None)) + assert len(ret) == 1 + ret = list(conf.option.find('prop')) assert len(ret) == 1 _is_same_opt(ret[0].option.get(), conf.option('gc.prop').option.get()) # conf.property.read_write() raises(AttributeError, "assert conf.option.find('prop').option.get()") - ret = conf.unrestraint.option.find(name='prop') + ret = list(conf.unrestraint.option.find(name='prop')) assert len(ret) == 2 _is_same_opt(ret[0].option.get(), conf.unrestraint.option('gc.gc2.prop').option.get()) _is_same_opt(ret[1].option.get(), conf.forcepermissive.option('gc.prop').option.get()) # - ret = conf.forcepermissive.option.find('prop') + ret = list(conf.forcepermissive.option.find('prop')) assert len(ret) == 1 _is_same_opt(ret[0].option.get(), conf.forcepermissive.option('gc.prop').option.get()) # _is_same_opt(conf.forcepermissive.option.find('prop', first=True).option.get(), conf.forcepermissive.option('gc.prop').option.get()) # combinaison of filters - ret = conf.unrestraint.option.find('prop', type=BoolOption) + ret = list(conf.unrestraint.option.find('prop', type=BoolOption)) assert len(ret) == 1 _is_same_opt(ret[0].option.get(), conf.unrestraint.option('gc.gc2.prop').option.get()) _is_same_opt(conf.unrestraint.option.find('prop', type=BoolOption, first=True).option.get(), conf.unrestraint.option('gc.gc2.prop').option.get()) # - ret = conf.option.find('dummy', value=False) + ret = list(conf.option.find('dummy', value=False)) assert len(ret) == 1 _is_same_opt(ret[0].option.get(), conf.option('gc.dummy').option.get()) # _is_same_opt(conf.option.find('dummy', value=False, first=True).option.get(), conf.option('gc.dummy').option.get()) #subconfig - ret = conf.option('gc').find('dummy') + ret = list(conf.option('gc').find('dummy')) assert len(ret) == 1 _is_same_opt(ret[0].option.get(), conf.option('gc.dummy').option.get()) # - ret = conf.option('gc').find('float') + ret = list(conf.option('gc').find('float')) assert len(ret) == 1 _is_same_opt(ret[0].option.get(), conf.option('gc.float').option.get()) # - ret = conf.option('gc').find('bool') + ret = list(conf.option('gc').find('bool')) assert len(ret) == 1 _is_same_opt(ret[0].option.get(), conf.option('gc.gc2.bool').option.get()) _is_same_opt(conf.option('gc').find('bool', value=False, first=True).option.get(), conf.option('gc.gc2.bool').option.get()) @@ -227,13 +228,13 @@ def test_find_in_config(): # raises(AttributeError, "conf.option('gc').find('wantref').option.get()") # - ret = conf.unrestraint.option('gc').find('prop') + ret = list(conf.unrestraint.option('gc').find('prop')) assert len(ret) == 2 _is_same_opt(ret[0].option.get(), conf.unrestraint.option('gc.gc2.prop').option.get()) _is_same_opt(ret[1].option.get(), conf.forcepermissive.option('gc.prop').option.get()) # conf.property.read_only() - ret = conf.option('gc').find('prop') + ret = list(conf.option('gc').find('prop')) assert len(ret) == 1 _is_same_opt(ret[0].option.get(), conf.option('gc.prop').option.get()) # not OptionDescription @@ -246,16 +247,16 @@ def test_find_multi(): o = OptionDescription('od', '', [b]) conf = Config(o) # - raises(AttributeError, "conf.option.find('bool', value=True)") - raises(AttributeError, "conf.option.find('bool', value=True, first=True)") + raises(AttributeError, "list(conf.option.find('bool', value=True))") + raises(AttributeError, "list(conf.option.find('bool', value=True, first=True))") conf.option('bool').value.set([False]) - raises(AttributeError, "conf.option.find('bool', value=True)") - raises(AttributeError, "conf.option.find('bool', value=True, first=True)") + raises(AttributeError, "list(conf.option.find('bool', value=True))") + raises(AttributeError, "list(conf.option.find('bool', value=True, first=True))") conf.option('bool').value.set([False, False]) - raises(AttributeError, "conf.option.find('bool', value=True)") - raises(AttributeError, "conf.option.find('bool', value=True, first=True)") + raises(AttributeError, "list(conf.option.find('bool', value=True))") + raises(AttributeError, "list(conf.option.find('bool', value=True, first=True))") conf.option('bool').value.set([False, False, True]) - ret = conf.option.find('bool', value=True) + ret = list(conf.option.find('bool', value=True)) assert len(ret) == 1 _is_same_opt(ret[0].option.get(), b) _is_same_opt(conf.option.find('bool', value=True, first=True).option.get(), b) @@ -264,7 +265,7 @@ def test_find_multi(): def test_does_not_find_in_config(): descr = make_description() conf = Config(descr) - raises(AttributeError, "conf.option.find('IDontExist')") + raises(AttributeError, "list(conf.option.find('IDontExist'))") def test_filename(): @@ -341,7 +342,11 @@ def test_help(): od1 = OptionDescription('o', '', [stro]) od2 = OptionDescription('o', '', [od1]) cfg = Config(od2) - cfg.help(_display=False, _valid=True) + cfg.help(_display=False) + cfg.config.help(_display=False) + cfg.option.help(_display=False) + cfg.option('o').help(_display=False) + cfg.option('o.s').help(_display=False) def test_config_reset(): diff --git a/test/test_dyn_optiondescription.py b/test/test_dyn_optiondescription.py index 580019c..f4f5c68 100644 --- a/test/test_dyn_optiondescription.py +++ b/test/test_dyn_optiondescription.py @@ -689,7 +689,7 @@ def test_find_dyndescription_context(): #assert len(opts) == 1 #assert isinstance(opts[0], DynSymLinkOption) #assert opts[0].impl_getname() == 'stval1' - raises(AttributeError, "api.option.find('strnotexists')") + raises(AttributeError, "list(api.option.find('strnotexists'))") def test_information_dyndescription_context(): diff --git a/test/test_metaconfig.py b/test/test_metaconfig.py index 9822734..cb7e191 100644 --- a/test/test_metaconfig.py +++ b/test/test_metaconfig.py @@ -145,7 +145,7 @@ def test_contexts(): def test_find(): meta = make_metaconfig() - ret = meta.option.find('i2') + ret = list(meta.option.find('i2')) assert len(ret) == 1 assert 1 == ret[0].value.get() assert 1 == meta.option.find('i2', first=True).value.get() diff --git a/test/test_option_setting.py b/test/test_option_setting.py index 9e73d33..f2cb6e9 100644 --- a/test/test_option_setting.py +++ b/test/test_option_setting.py @@ -383,7 +383,7 @@ def test_allow_multiple_changes_from_config(): def test_access_by_get(): descr = make_description() api = Config(descr) - raises(AttributeError, "api.option.find('idontexist')") + raises(AttributeError, "list(api.option.find('idontexist'))") assert api.option.find('wantref', first=True).value.get() is False assert api.option.find('dummy', first=True).value.get() is False diff --git a/tiramisu/__init__.py b/tiramisu/__init__.py index bd16879..ff4a491 100644 --- a/tiramisu/__init__.py +++ b/tiramisu/__init__.py @@ -15,7 +15,7 @@ from .function import Params, ParamOption, ParamValue, ParamContext from .option import * from .error import APIError -from .api import getapi, Config, MetaConfig, GroupConfig +from .api import Config, MetaConfig, GroupConfig from .option import __all__ as all_options from .setting import owners, undefined @@ -27,7 +27,6 @@ allfuncs = ['Params', 'MetaConfig', 'GroupConfig', 'Config', - 'getapi', 'APIError', 'undefined'] allfuncs.extend(all_options) diff --git a/tiramisu/api.py b/tiramisu/api.py index 21a6a81..a004ad9 100644 --- a/tiramisu/api.py +++ b/tiramisu/api.py @@ -29,233 +29,225 @@ from .option import ChoiceOption, OptionDescription TIRAMISU_VERSION = 3 -EXCLUDE_HELP = ('help', '_get_option', '_test_slave_index') - - class TiramisuHelp: - icon = '\u2937' - tmpl_help = '{0}{1} {2}: \n{0} {3}\n' + _tmpl_help = ' {0}\t{1}' def help(self, - init: bool=True, - space: str="", - root: str='', - _display: bool=True, - _valid: bool=False) -> List[str]: + _display: bool=True) -> List[str]: + def display(doc=''): + if _display: # pragma: no cover + print(doc) options = [] - if init and isinstance(self, TiramisuAPI): - options.append(self.tmpl_help.format(space, self.icon, root + 'unrestraint', _('access to option without property restriction'))) - options.append(self.tmpl_help.format(space, self.icon, root + 'forcepermissive', _('access to option without verifying permissive property'))) - root = '[unrestraint.|forcepermissive.]' - if 'registers' in dir(self): - modules = list(self.registers.keys()) - modules.sort() - for module_name in modules: - module = self.registers[module_name] - try: - instance_module = module(None) - except TypeError: - instance_module = module(None, None, None) - if isinstance(instance_module, TiramisuDispatcher): - if _valid and not getdoc(module.__call__): # pragma: no cover - raise Exception('unknown doc for {}'.format('__call__')) - module_doc = _(getdoc(module.__call__)) - module_signature = signature(module.__call__) - module_args = [str(module_signature.parameters[key]) for key in list(module_signature.parameters.keys())[1:]] - module_args = '(' + ', '.join(module_args) + ')' - options.append(self.tmpl_help.format(space, self.icon, root + module_name + module_args, module_doc)) - if hasattr(module, 'subhelp'): - instance_submodule = module.subhelp(None, None, None, None, None) - options.extend(instance_submodule.help(init=False, space=space + ' ', root=root + module_name + module_args + '.')) - else: - root = root + '[config(path).]' - if isinstance(instance_module, CommonTiramisuOption): - if _valid and not getdoc(module): # pragma: no cover - raise Exception('unknown doc for {}'.format(module.__class__.__name__)) - module_doc = _(getdoc(module)) - options.append(self.tmpl_help.format(space, self.icon, root + module_name, module_doc)) - if isinstance(instance_module, TiramisuContext): - if _valid and not getdoc(module): # pragma: no cover - raise Exception('unknown doc for {}'.format(module.__class__.__name__)) - module_doc = _(getdoc(module)) - options.append(self.tmpl_help.format(space, self.icon, root + module_name, module_doc)) - options.extend(instance_module.help(init=False, space=space + ' ', root=root + '{}.'.format(module_name))) + all_modules = dir(self) + modules = [] + max_len = 0 + force = False + for module_name in all_modules: + if module_name in ['forcepermissive', 'unrestraint']: + force = True + max_len = max(max_len, len('forcepermissive')) + elif module_name is not 'help' and not module_name.startswith('_'): + modules.append(module_name) + max_len = max(max_len, len(module_name)) + modules.sort() - funcs = dir(self) - funcs.sort() - for func_name in funcs: - if not func_name.startswith('__') and not func_name in EXCLUDE_HELP: - func = getattr(self, func_name) - if ismethod(func): - module_signature = signature(func) - module_args = list(module_signature.parameters.keys()) - module_args = [str(module_signature.parameters[key]) for key in module_signature.parameters.keys()] - module_args = '(' + ', '.join(module_args) + ')' - if func_name.startswith('_'): - func_name = func_name[1:] - if _valid and not getdoc(func): # pragma: no cover - raise Exception('unknown doc for {}'.format(func.__name__)) - options.append(self.tmpl_help.format(space, self.icon, root + func_name + module_args, _(getdoc(func)))) - if init: - if _display: # pragma: no cover - print('\n'.join(options)) - else: - return options + display(_(getdoc(self))) + display() + if force: + display(_('Settings:')) + display(self._tmpl_help.format('forcepermissive', _('Access to option without verifying permissive properties')).expandtabs(max_len + 10)) + display(self._tmpl_help.format('unrestraint', _('Access to option without property restriction')).expandtabs(max_len + 10)) + display() + if isinstance(self, TiramisuDispatcher): + doc = _(getdoc(self.__call__)) + display(_('Call: {}').format(doc)) + display() + display(_('Commands:')) + for module_name in modules: + module = getattr(self, module_name) + doc = _(getdoc(module)) + display(self._tmpl_help.format(module_name, doc).expandtabs(max_len + 10)) + display() + + def __dir__(self): + if '_registers' in super().__dir__(): + return list(self._registers.keys()) + return super().__dir__() class CommonTiramisu(TiramisuHelp): - allow_optiondescription = True - registers = {} + _allow_optiondescription = True def _get_option(self) -> Any: - option = self.option_bag.option + 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()) - self.option_bag.set_option(option, - self.option_bag.path, - self.option_bag.index, - self.option_bag.config_bag) - self.option_bag.config_bag.context.cfgimpl_get_settings().validate_properties(self.option_bag) - index = self.option_bag.index + option = self._subconfig.cfgimpl_get_description().impl_getchild(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, + self._option_bag.config_bag) + self._option_bag.config_bag.context.cfgimpl_get_settings().validate_properties(self._option_bag) + index = self._option_bag.index if index is not None: if option.impl_is_optiondescription() or not option.impl_is_master_slaves('slave'): raise APIError('index must be set only with a slave option') - self._length = self.subconfig.cfgimpl_get_length_slave(self.option_bag) + self._length = self._subconfig.cfgimpl_get_length_slave(self._option_bag) if index >= self._length: raise SlaveError(_('index "{}" is higher than the master length "{}" ' 'for option "{}"').format(index, self._length, option.impl_get_display_name())) - if not self.allow_optiondescription and option.impl_is_optiondescription(): + if not self._allow_optiondescription and option.impl_is_optiondescription(): raise APIError(_('option must not be an optiondescription')) return option class CommonTiramisuOption(CommonTiramisu): - allow_optiondescription = False - slave_need_index = True + _allow_optiondescription = False + _slave_need_index = True def __init__(self, name: str, subconfig: Union[KernelConfig, SubConfig], option_bag: OptionBag) -> None: - self.option_bag = option_bag + self._option_bag = option_bag self._name = name - self.subconfig = subconfig + self._subconfig = subconfig # for help() - if option_bag is not None and self.option_bag.config_bag.context.impl_type != 'group': + if option_bag is not None and self._option_bag.config_bag.context.impl_type != 'group': self._get_option() - if option_bag.config_bag is not None and self.slave_need_index: + if option_bag.config_bag is not None and self._slave_need_index: self._test_slave_index() def _test_slave_index(self) -> None: - option = self.option_bag.option + option = self._option_bag.option if not option.impl_is_optiondescription(): - if self.option_bag.index is None and option.impl_is_master_slaves('slave'): - raise APIError(_('index must be set with the slave option "{}"').format(self.option_bag.path)) - elif self.option_bag.index is not None and not option.impl_is_master_slaves('slave'): - raise APIError(_('index must be set only with a slave option, not for "{}"').format(self.option_bag.path)) # pragma: no cover + if self._option_bag.index is None and option.impl_is_master_slaves('slave'): + raise APIError(_('index must be set with the slave option "{}"').format(self._option_bag.path)) + elif self._option_bag.index is not None and not option.impl_is_master_slaves('slave'): + raise APIError(_('index must be set only with a slave option, not for "{}"').format(self._option_bag.path)) - def __getattr__(self, name): # pragma: no cover - if not hasattr(CommonTiramisuOption, name): - raise APIError(_('unknown method {}').format(name)) - else: - super().__getattribute__(name) + def __getattr__(self, name): + raise APIError(_('unknown method {}').format(name)) -class TiramisuOptionOption(CommonTiramisuOption): - """manage option""" - allow_optiondescription = True - slave_need_index = False +class _TiramisuOptionOptionDescription(CommonTiramisuOption): + """Manage option""" + _allow_optiondescription = True + _slave_need_index = False def get(self): - """get Tiramisu option""" - return self.option_bag.option - - def _ismulti(self): - """test if option could have multi value""" - option = self.option_bag.option - return option.impl_is_multi() - - def _issubmulti(self): - """test if option could have submulti value""" - option = self.option_bag.option - return option.impl_is_submulti() + """Get Tiramisu option""" + return self._option_bag.option def ismasterslaves(self): - """test if option is a master or a slave""" - option = self.option_bag.option + """Test if option is a master or a slave""" + option = self._option_bag.option return option.impl_is_master_slaves() - def _ismaster(self): - """test if option is a master""" - option = self.option_bag.option - return option.impl_is_master_slaves('master') - - def _isslave(self): - """test if option is a slave""" - option = self.option_bag.option - return option.impl_is_master_slaves('slave') - def doc(self): - """get option document""" - option = self.option_bag.option + """Get option document""" + option = self._option_bag.option return option.impl_get_display_name() def name(self): - """get option name""" + """Get option name""" return self._name def path(self) -> str: - """get option path""" - return self.option_bag.path - - def _default(self): - """get default value for an option (not for optiondescription)""" - option = self.option_bag.option - return option.impl_getdefault() - - def _defaultmulti(self): - """get default value when added a value for a multi option (not for optiondescription)""" - option = self.option_bag.option - return option.impl_getdefault_multi() + """Get option path""" + return self._option_bag.path def has_dependency(self, self_is_dep=True): - """test if option has dependency""" - option = self.option_bag.option + """Test if option has dependency""" + option = self._option_bag.option return option.impl_has_dependency(self_is_dep) - def _consistencies(self): - """get consistencies for an option (not for optiondescription)""" - option = self.option_bag.option - return option.get_consistencies() - - def _callbacks(self): - """get callbacks for an option (not for optiondescription)""" - option = self.option_bag.option - return option.impl_get_callback() - def requires(self): - """get requires for an option""" - option = self.option_bag.option + """Get requires for an option""" + option = self._option_bag.option return option.impl_getrequires() - def __getattr__(self, name: str) -> Callable: - option = self.option_bag.option - if not option.impl_is_optiondescription() and not name.startswith('_'): - return getattr(self, '_' + name) - raise APIError(_('{} is unknown').format(name)) # pragma: no cover - def isoptiondescription(self): - """test if option is an optiondescription""" - option = self.option_bag.option + """Test if option is an optiondescription""" + option = self._option_bag.option return option.impl_is_optiondescription() +class _TiramisuOptionOption(_TiramisuOptionOptionDescription): + """Manage option""" + def ismulti(self): + """Test if option could have multi value""" + option = self._option_bag.option + return option.impl_is_multi() + + def issubmulti(self): + """Test if option could have submulti value""" + option = self._option_bag.option + return option.impl_is_submulti() + + def ismaster(self): + """Test if option is a master""" + option = self._option_bag.option + return option.impl_is_master_slaves('master') + + def isslave(self): + """Test if option is a slave""" + option = self._option_bag.option + return option.impl_is_master_slaves('slave') + + def default(self): + """Get default value for an option (not for optiondescription)""" + option = self._option_bag.option + return option.impl_getdefault() + + def defaultmulti(self): + """Get default value when added a value for a multi option (not for optiondescription)""" + option = self._option_bag.option + return option.impl_getdefault_multi() + + def consistencies(self): + """Get consistencies for an option (not for optiondescription)""" + option = self._option_bag.option + return option.get_consistencies() + + def callbacks(self): + """Get callbacks for an option (not for optiondescription)""" + option = self._option_bag.option + return option.impl_get_callback() + + +class TiramisuOptionOption(CommonTiramisuOption): + """Manage option""" + _allow_optiondescription = True + _slave_need_index = False + + def __new__(cls, + name, + subconfig, + option_bag): + cls._name = name + cls._subconfig = subconfig + cls._option_bag = option_bag + cls._get_option(cls) + option = option_bag.option + del cls._name + del cls._subconfig + del cls._option_bag + if option.impl_is_optiondescription(): + return _TiramisuOptionOptionDescription(name=name, + subconfig=subconfig, + option_bag=option_bag) + else: + return _TiramisuOptionOption(name=name, + subconfig=subconfig, + option_bag=option_bag) + + class TiramisuOptionOwner(CommonTiramisuOption): - """manager option's owner""" + """Manage option's owner""" def __init__(self, name: str, @@ -267,34 +259,34 @@ class TiramisuOptionOwner(CommonTiramisuOption): option_bag) if option_bag is not None: # for help() - self.values = self.option_bag.config_bag.context.cfgimpl_get_values() + self._values = self._option_bag.config_bag.context.cfgimpl_get_values() def get(self): - """get owner for a specified option""" - option = self.option_bag.option - return self.values.getowner(self.option_bag) + """Get owner for a specified option""" + option = self._option_bag.option + return self._values.getowner(self._option_bag) def isdefault(self): - """is option has defaut value""" - option = self.option_bag.option - return self.values.is_default_owner(self.option_bag) + """Is option has defaut value""" + option = self._option_bag.option + return self._values.is_default_owner(self._option_bag) def set(self, owner): - """get owner for a specified option""" - option = self.option_bag.option + """Get owner for a specified option""" + option = self._option_bag.option try: obj_owner = getattr(owners, owner) except AttributeError: owners.addowner(owner) obj_owner = getattr(owners, owner) - self.values.setowner(obj_owner, - self.option_bag) + self._values.setowner(obj_owner, + self._option_bag) class TiramisuOptionProperty(CommonTiramisuOption): - """manager option's property""" - allow_optiondescription = True - slave_need_index = False + """Manage option's property""" + _allow_optiondescription = True + _slave_need_index = False def __init__(self, name: str, @@ -304,53 +296,53 @@ class TiramisuOptionProperty(CommonTiramisuOption): subconfig, option_bag) if option_bag and option_bag.config_bag: - self.settings = option_bag.config_bag.context.cfgimpl_get_settings() + self._settings = option_bag.config_bag.context.cfgimpl_get_settings() def get(self, apply_requires=True): - """get properties for an option""" - option = self.option_bag.option + """Get properties for an option""" + option = self._option_bag.option if apply_requires: self._test_slave_index() - properties = self.option_bag.properties + properties = self._option_bag.properties else: - properties = self.settings.getproperties(self.option_bag, + properties = self._settings.getproperties(self._option_bag, apply_requires=False) return set(properties) def add(self, prop): - """add new property for an option""" - option = self.option_bag.option + """Add new property for an option""" + option = self._option_bag.option if prop in FORBIDDEN_SET_PROPERTIES: raise ConfigError(_('cannot add this property: "{0}"').format( ' '.join(prop))) - props = self.settings.getproperties(self.option_bag, + props = self._settings.getproperties(self._option_bag, apply_requires=False) - self.settings.setproperties(self.option_bag.path, + self._settings.setproperties(self._option_bag.path, props | {prop}, - self.option_bag, - self.option_bag.config_bag.context) + self._option_bag, + self._option_bag.config_bag.context) def pop(self, prop): - """remove new property for an option""" - option = self.option_bag.option - props = self.settings.getproperties(self.option_bag, + """Remove new property for an option""" + option = self._option_bag.option + props = self._settings.getproperties(self._option_bag, apply_requires=False) - self.settings.setproperties(self.option_bag.path, + self._settings.setproperties(self._option_bag.path, props - {prop}, - self.option_bag, - self.option_bag.config_bag.context) + self._option_bag, + self._option_bag.config_bag.context) def reset(self): - """reset all personalised properties""" - option = self.option_bag.option - self.settings.reset(self.option_bag, - self.option_bag.config_bag.context) + """Reset all personalised properties""" + option = self._option_bag.option + self._settings.reset(self._option_bag, + self._option_bag.config_bag.context) class TiramisuOptionPermissive(CommonTiramisuOption): - """manager option's property""" - allow_optiondescription = True - slave_need_index = False + """Manage option's permissive""" + _allow_optiondescription = True + _slave_need_index = False # FIXME should have same api than property def __init__(self, @@ -361,138 +353,153 @@ class TiramisuOptionPermissive(CommonTiramisuOption): subconfig, option_bag) if option_bag and option_bag.config_bag: - self.settings = option_bag.config_bag.context.cfgimpl_get_settings() + self._settings = option_bag.config_bag.context.cfgimpl_get_settings() def get(self): - """get permissives value""" - return self.settings.getpermissives(self.option_bag.option, - self.option_bag.path) + """Get permissives value""" + return self._settings.getpermissives(self._option_bag.option, + self._option_bag.path) def set(self, permissives): - """set permissives value""" - option = self.option_bag.option - self.settings.setpermissives(self.option_bag, - permissives=permissives) + """Set permissives value""" + option = self._option_bag.option + self._settings.setpermissives(self._option_bag, + permissives=permissives) def reset(self): - """reset all personalised permissive""" + """Reset all personalised permissive""" self.set(frozenset()) class TiramisuOptionInformation(CommonTiramisuOption): - """manage option informations""" - allow_optiondescription = True - slave_need_index = False + """Manage option's informations""" + _allow_optiondescription = True + _slave_need_index = False def get(self, key, default=undefined): - """get information for a key name""" - path = self.option_bag.path - values = self.option_bag.config_bag.context.cfgimpl_get_values() + """Get information""" + path = self._option_bag.path + values = self._option_bag.config_bag.context.cfgimpl_get_values() try: return values.get_information(key, default, path=path) except ValueError: - option = self.option_bag.option + option = self._option_bag.option return option.impl_get_information(key, default) def set(self, key, value): - """set information for a key name""" - path = self.option_bag.path - values = self.option_bag.config_bag.context.cfgimpl_get_values() + """Set information""" + path = self._option_bag.path + values = self._option_bag.config_bag.context.cfgimpl_get_values() values.set_information(key, value, path=path) def reset(self, key): - """remove information for a key name""" - path = self.option_bag.path - values = self.option_bag.config_bag.context.cfgimpl_get_values() + """Remove information""" + path = self._option_bag.path + values = self._option_bag.config_bag.context.cfgimpl_get_values() values.del_information(key, path=path) + def list(self): + """List information's keys""" + path = self._option_bag.path + values = self._option_bag.config_bag.context.cfgimpl_get_values() + return values.list_information(path) -class TiramisuOptionValue(CommonTiramisuOption): - """manager option's value""" - allow_optiondescription = True - slave_need_index = False - def _o_get(self): - """get option's value""" - option = self.option_bag.option +class _TiramisuOptionValueOption: + def get(self): + """Get option's value""" + option = self._option_bag.option self._test_slave_index() - return self.subconfig.getattr(self._name, - self.option_bag) + return self._subconfig.getattr(self._name, + self._option_bag) - def _o_set(self, value): - """set a value for a specified option""" - option = self.option_bag.option + def set(self, value): + """Change option's value""" + option = self._option_bag.option self._test_slave_index() - values = self.option_bag.config_bag.context.cfgimpl_get_values() + values = self._option_bag.config_bag.context.cfgimpl_get_values() if isinstance(value, list): while undefined in value: idx = value.index(undefined) - value[idx] = values.getdefaultvalue(self.option_bag, + value[idx] = values.getdefaultvalue(self._option_bag, force_index=idx) elif value == undefined: - value = values.getdefaultvalue(self.option_bag) - self.subconfig.setattr(value, - self.option_bag) + value = values.getdefaultvalue(self._option_bag) + self._subconfig.setattr(value, + self._option_bag) - def _m_pop(self, index): - """pop value for a master option (only for master option)""" - assert not self.option_bag.option.impl_is_symlinkoption(), _("can't delete a SymLinkOption") - self.option_bag.config_bag.context.cfgimpl_get_values().reset_master(index, - self.option_bag, - self.subconfig) - - def _o_reset(self): - """reset value for a value""" + def reset(self): + """Reset value for an option""" self._test_slave_index() - self.subconfig.delattr(self.option_bag) + self._subconfig.delattr(self._option_bag) - def _m_reset(self, - itself: bool=True, - children: bool=False): - """reset value for a MetaConfig""" + +class _TiramisuOptionValueMaster: + def pop(self, index): + """Pop a value""" + assert not self._option_bag.option.impl_is_symlinkoption(), _("can't delete a SymLinkOption") + self._option_bag.config_bag.context.cfgimpl_get_values().reset_master(index, + self._option_bag, + self._subconfig) + + def len(self): + """Length of master option""" + option = self._option_bag.option + # for example if index is None + if '_length' not in vars(self): + self._length = self._subconfig.cfgimpl_get_length() + return self._length + + +class _TiramisuOptionValueMeta: + def reset(self, + itself: bool=True, + children: bool=False): + """Reset value""" if children: - config_bag = self.option_bag.config_bag - config_bag.context.reset(self.option_bag.path, + config_bag = self._option_bag.config_bag + config_bag.context.reset(self._option_bag.path, config_bag) if itself: - self._o_reset() + self._test_slave_index() + self._subconfig.delattr(self._option_bag) - def _g_reset(self): - """reset value for a GroupConfig""" - self.option_bag.config_bag.context.reset(self.option_bag.path) - def _m_len_master(self): - """length of master option (only for slave option)""" - option = self.option_bag.option +class _TiramisuOptionValueGroup: + def reset(self): + """Reset value""" + self._option_bag.config_bag.context.reset(self._option_bag.path) + + +class _TiramisuOptionValueSlave: + def len(self): + """Length of slave option""" + option = self._option_bag.option # for example if index is None if '_length' not in vars(self): - self._length = self.subconfig.cfgimpl_get_length() + self._length = self._subconfig.cfgimpl_get_length_slave(self._option_bag) return self._length - def _s_len_slave(self): - """length of slave option (only for slave option)""" - option = self.option_bag.option - # for example if index is None - if '_length' not in vars(self): - self._length = self.subconfig.cfgimpl_get_length_slave(self.option_bag) - return self._length - def _c_list(self): - """all values available for an option (only for choiceoption)""" - option = self.option_bag.option - return option.impl_get_values(self.option_bag) +class _TiramisuOptionValueChoiceOption: + def list(self): + """All values available for a ChoiceOption""" + option = self._option_bag.option + return option.impl_get_values(self._option_bag) - def _od_dict(self, - flatten=False, - withvalue=undefined, - withoption=None, - fullpath=False): - """return dict with path as key and value (only for optiondescription)""" + +class _TiramisuOptionValueOptionDescription: + def dict(self, + flatten=False, + withvalue=undefined, + withoption=None, + fullpath=False): + """Dict with path as key and value""" self._get_option() - name = self.option_bag.option.impl_getname() - subconfig = self.subconfig.get_subconfig(name, - self.option_bag) - config_bag = self.option_bag.config_bag + name = self._option_bag.option.impl_getname() + subconfig = self._subconfig.get_subconfig(name, + self._option_bag) + config_bag = self._option_bag.config_bag if config_bag.properties and 'warnings' in config_bag.properties: config_bag = config_bag.copy() config_bag.properties = config_bag.properties - {'warnings'} @@ -502,170 +509,191 @@ class TiramisuOptionValue(CommonTiramisuOption): withoption=withoption, withvalue=withvalue) - def __getattr__(self, name: str) -> Callable: - option = self.option_bag.option - if name.startswith('_'): - # not a valid function - pass - elif name == 'list' and isinstance(option, ChoiceOption): - return self._c_list - elif name == 'pop' and option.impl_is_master_slaves('master'): - return self._m_pop - elif name == 'len': - if option.impl_is_master_slaves('slave'): - return self._s_len_slave - if option.impl_is_master_slaves('master'): - return self._m_len_master - elif name == 'dict' and option.impl_is_optiondescription(): - return self._od_dict - elif name == 'reset': - if self.option_bag.config_bag.context.impl_type == 'group': - return getattr(self, '_g_' + name) - elif not option.impl_is_optiondescription(): - if self.option_bag.config_bag.context.impl_type == 'meta': - return getattr(self, '_m_' + name) - return getattr(self, '_o_' + name) - elif option and not option.impl_is_optiondescription(): - return getattr(self, '_o_' + name) - raise APIError(_('{} is unknown').format(name)) + +class TiramisuOptionValue(CommonTiramisuOption): + """Manage option's value""" + _allow_optiondescription = True + _slave_need_index = False + + def __new__(cls, + name, + subconfig, + option_bag): + if subconfig is not None: + cls._name = name + cls._subconfig = subconfig + cls._option_bag = option_bag + cls._get_option(cls) + option = option_bag.option + del cls._name + del cls._subconfig + del cls._option_bag + else: + option = None + types = [CommonTiramisuOption] + if option: + if option.impl_is_optiondescription(): + types.append(_TiramisuOptionValueOptionDescription) + else: + types.append(_TiramisuOptionValueOption) + if isinstance(option, ChoiceOption): + types.append(_TiramisuOptionValueChoiceOption) + if option.impl_is_master_slaves('master'): + types.append(_TiramisuOptionValueMaster) + elif option.impl_is_master_slaves('slave'): + types.append(_TiramisuOptionValueSlave) + if option_bag.config_bag.context.impl_type == 'meta': + # only if not an optiondescription + types.insert(0, _TiramisuOptionValueMeta) + if option_bag.config_bag.context.impl_type == 'group': + types.append(_TiramisuOptionValueGroup) + new_type_dict = {'_allow_optiondescription': cls._allow_optiondescription, + '_slave_need_index': cls._slave_need_index} + new_type = type('TiramisuOptionValue', tuple(types), new_type_dict)(name=name, + subconfig=subconfig, + option_bag=option_bag) + new_type.__doc__ = cls.__doc__ + return new_type -def registers(registers: Dict[str, type], prefix: str) -> None: +def _registers(_registers: Dict[str, type], + prefix: str, + extra_type: Optional[type]=None) -> None: for module_name in globals().keys(): if module_name != prefix and module_name.startswith(prefix): module = globals()[module_name] func_name = module_name[len(prefix):].lower() - registers[func_name] = module + _registers[func_name] = module -class TiramisuOption(CommonTiramisu): - registers = {} +class _TiramisuOption(CommonTiramisu): + """Manage selected option""" + _registers = {} def __init__(self, name: Optional[str], path: Optional[str]=None, index: Optional[int]=None, subconfig: Union[None, KernelConfig, SubConfig]=None, - config_bag: Optional[ConfigBag]=None, - option_bag: Optional[OptionBag]=None) -> None: + config_bag: Optional[ConfigBag]=None) -> None: self._name = name - self.subconfig = subconfig + self._subconfig = subconfig self._path = path - self.index = index - self.config_bag = config_bag - self.option_bag = OptionBag() - self.option_bag.path = self._path - self.option_bag.index = self.index - self.option_bag.config_bag = self.config_bag - if not self.registers: - registers(self.registers, self.__class__.__name__) + self._index = index + self._config_bag = config_bag + self._option_bag = OptionBag() + self._option_bag.path = self._path + self._option_bag.index = self._index + self._option_bag.config_bag = self._config_bag + if not self._registers: + _registers(self._registers, 'TiramisuOption') def __getattr__(self, subfunc: str) -> Any: - if subfunc in self.registers: - return self.registers[subfunc](self._name, - self.subconfig, - self.option_bag) - elif self._get_option().impl_is_optiondescription() and not subfunc.startswith('_'): - return getattr(self, '_' + subfunc) + if subfunc in self._registers: + return self._registers[subfunc](self._name, + self._subconfig, + self._option_bag) raise APIError(_('please specify a valid sub function ({})').format(subfunc)) # pragma: no cover - def _find(self, - name: str, - value=undefined, - type=None, - first: bool=False): + +class _TiramisuOptionDescription(_TiramisuOption): + def find(self, + name: str, + value=undefined, + type=None, + first: bool=False): """find an option by name (only for optiondescription)""" if not first: ret = [] option = self._get_option() oname = option.impl_getname() - path = self.subconfig._get_subpath(oname) + path = self._subconfig._get_subpath(oname) option_bag = OptionBag() option_bag.set_option(option, path, None, - self.config_bag) - subconfig = self.subconfig.get_subconfig(oname, + self._config_bag) + subconfig = self._subconfig.get_subconfig(oname, option_bag) for path in subconfig.find(byname=name, byvalue=value, bytype=type, _subpath=self._path, - config_bag=self.config_bag): - subconfig, name = self.config_bag.context.cfgimpl_get_home_by_path(path, - self.config_bag) + config_bag=self._config_bag): + subconfig, name = self._config_bag.context.cfgimpl_get_home_by_path(path, + self._config_bag) t_option = TiramisuOption(name, path, None, # index for a slave ? subconfig, - self.config_bag) + self._config_bag) if first: return t_option ret.append(t_option) return ret # -# def _get(self, name): +# def get(self, name): # self._get_option() -# current_option = self.option_bag.option.impl_getchild(name, -# self.config_bag, -# self.subconfig.cfgimpl_get_path) -# path = self.option_bag.path + '.' + name +# current_option = self._option_bag.option.impl_getchild(name, +# self._config_bag, +# self._subconfig.cfgimpl_get_path) +# path = self._option_bag.path + '.' + name # option_bag= OptionBag() # option_bag.set_option(current_option, # path, # None, -# self.config_bag) +# self._config_bag) # if current_option.impl_is_optiondescription(): -# subconfig = self.subconfig.getattr(name, +# subconfig = self._subconfig.getattr(name, # option_bag) # else: -# subconfig = self.subconfig +# subconfig = self._subconfig # return TiramisuOption(name, # path, # None, # subconfig, -# self.config_bag, +# self._config_bag, # option_bag) - def _group_type(self): - """get type for an optiondescription (only for optiondescription)""" + def group_type(self): + """Get type for an optiondescription (only for optiondescription)""" return self._get_option().impl_get_group_type() - def _list(self, - type='option', - group_type=None): - """list options in an optiondescription (only for optiondescription)""" + def list(self, + type='option', + group_type=None): + """List options in an optiondescription (only for optiondescription)""" if type not in ('all', 'option', 'optiondescription'): - raise APIError(_('unknown list type {}').format(type)) # pragma: no cover + raise APIError(_('unknown list type {}').format(type)) if group_type is not None and not isinstance(group_type, groups.GroupType): - raise TypeError(_("unknown group_type: {0}").format(group_type)) # pragma: no cover + raise TypeError(_("unknown group_type: {0}").format(group_type)) def _filter(opt): - if self.config_bag.properties: + if self._config_bag.properties: name = opt.impl_getname() path = subconfig._get_subpath(name) option_bag = OptionBag() option_bag.set_option(opt, path, None, - self.config_bag) + self._config_bag) if opt.impl_is_optiondescription(): - self.subconfig.get_subconfig(name, - option_bag) + self._subconfig.get_subconfig(name, + option_bag) else: subconfig.getattr(name, option_bag) option = self._get_option() name = option.impl_getname() - path = self.subconfig._get_subpath(name) + path = self._subconfig._get_subpath(name) option_bag = OptionBag() option_bag.set_option(option, path, None, - self.config_bag) - subconfig = self.subconfig.get_subconfig(name, - option_bag) - for opt in option.impl_getchildren(self.config_bag): + self._config_bag) + subconfig = self._subconfig.get_subconfig(name, + option_bag) + for opt in option.impl_getchildren(self._config_bag): try: subsubconfig = _filter(opt) except PropertiesOptionError: @@ -681,35 +709,76 @@ class TiramisuOption(CommonTiramisu): subconfig._get_subpath(name), None, subconfig, - self.config_bag) + self._config_bag) + + +class TiramisuOption(CommonTiramisuOption): + """Manage selected option""" + def __new__(cls, + name: Optional[str], + path: Optional[str]=None, + index: Optional[int]=None, + 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()) + if option.impl_is_optiondescription(): + return _TiramisuOptionDescription(name=name, + path=path, + index=index, + subconfig=subconfig, + config_bag=config_bag) + return _TiramisuOption(name=name, + path=path, + index=index, + subconfig=subconfig, + config_bag=config_bag) + +#__________________________________________________________________________________________________ +# +# First part of API: +# - contexts informations: +# - context owner +# - context information +# - context property +# - context permissive +# - forcepermissive +# - unrestraint +# - manage MetaConfig or GroupConfig class TiramisuContext(TiramisuHelp): def __init__(self, config_bag: Optional[ConfigBag]) -> None: - self.config_bag = config_bag + self._config_bag = config_bag class TiramisuContextInformation(TiramisuContext): - """manage configuration informations""" + """Manage config informations""" def get(self, name, default=undefined): - """get information for a key name""" - return self.config_bag.context.impl_get_information(name, default) + """Get an information""" + return self._config_bag.context.impl_get_information(name, default) def set(self, name, value): - """set information for a key name""" - self.config_bag.context.impl_set_information(name, value) + """Set an information""" + self._config_bag.context.impl_set_information(name, value) def reset(self, name): - """remove information for a key name""" - self.config_bag.context.impl_del_information(name) + """Remove an information""" + self._config_bag.context.impl_del_information(name) + + def list(self): + """List information's keys""" + return self._config_bag.context.impl_list_information() class TiramisuContextValue(TiramisuContext): - """manager value""" + """Manage config value""" def mandatory_warnings(self): - """return path of options with mandatory property without any value""" - return self.config_bag.context.cfgimpl_get_values().mandatory_warnings(self.config_bag) + """Return path of options with mandatory property without any value""" + return self._config_bag.context.cfgimpl_get_values().mandatory_warnings(self._config_bag) def set(self, path: str, @@ -719,7 +788,7 @@ class TiramisuContextValue(TiramisuContext): force_default=undefined, force_default_if_same=undefined, force_dont_change_value=undefined): - """set values for a GroupConfig or a MetaConfig""" + """Set a value in config or children for a path""" kwargs = {} if only_config is not undefined: kwargs['only_config'] = only_config @@ -729,10 +798,10 @@ class TiramisuContextValue(TiramisuContext): kwargs['force_default_if_same'] = force_default_if_same if force_dont_change_value is not undefined: kwargs['force_dont_change_value'] = force_dont_change_value - return self.config_bag.context.set_value(path, + return self._config_bag.context.set_value(path, index, value, - self.config_bag, + self._config_bag, **kwargs) def dict(self, @@ -740,12 +809,12 @@ class TiramisuContextValue(TiramisuContext): withvalue=undefined, withoption=None, fullpath=False): - """return dict with path as key and value""" - if not self.config_bag.properties: - config_bag = self.config_bag + """Dict with path as key and value""" + if not self._config_bag.properties: + config_bag = self._config_bag else: - config_bag = self.config_bag.copy() - config_bag.properties = self.config_bag.properties - {'warnings'} + config_bag = self._config_bag.copy() + config_bag.properties = self._config_bag.properties - {'warnings'} return config_bag.context.make_dict(config_bag, flatten=flatten, fullpath=fullpath, @@ -754,8 +823,8 @@ class TiramisuContextValue(TiramisuContext): def exportation(self, with_default_owner: bool=False): - """export all values""" - exportation = self.config_bag.context.cfgimpl_get_values()._p_.exportation() + """Export all values""" + exportation = self._config_bag.context.cfgimpl_get_values()._p_.exportation() if not with_default_owner: exportation = [list(exportation[0]), list(exportation[1]), list(exportation[2]), list(exportation[3])] index = exportation[0].index(None) @@ -766,15 +835,15 @@ class TiramisuContextValue(TiramisuContext): return exportation def importation(self, values): - """import values""" + """Import values""" if None not in values[0]: - context_owner = self.config_bag.context.cfgimpl_get_values().get_context_owner() + context_owner = self._config_bag.context.cfgimpl_get_values().get_context_owner() else: context_owner = None - self.config_bag.context.cfgimpl_get_values()._p_.importation(values) - self.config_bag.context.cfgimpl_reset_cache(None, None) + self._config_bag.context.cfgimpl_get_values()._p_.importation(values) + self._config_bag.context.cfgimpl_reset_cache(None, None) if context_owner is not None: - self.config_bag.context.cfgimpl_get_values()._p_.setvalue(None, + self._config_bag.context.cfgimpl_get_values()._p_.setvalue(None, None, context_owner, None, @@ -782,161 +851,160 @@ class TiramisuContextValue(TiramisuContext): class TiramisuContextOwner(TiramisuContext): - """manager value""" + """Global owner""" def get(self): - """get default owner""" - return self.config_bag.context.cfgimpl_get_values().get_context_owner() + """Get owner""" + return self._config_bag.context.cfgimpl_get_values().get_context_owner() def set(self, owner): - """set default owner""" + """Set owner""" try: obj_owner = getattr(owners, owner) except AttributeError: owners.addowner(owner) obj_owner = getattr(owners, owner) - self.config_bag.context.cfgimpl_get_values().set_context_owner(obj_owner) + self._config_bag.context.cfgimpl_get_values().set_context_owner(obj_owner) class TiramisuContextProperty(TiramisuContext): - """manage configuration properties""" + """Manage config properties""" def read_only(self): - """set configuration to read only mode""" - settings = self.config_bag.context.cfgimpl_get_settings() - settings.read_only(self.config_bag.context) - del self.config_bag.properties + """Set config to read only mode""" + settings = self._config_bag.context.cfgimpl_get_settings() + settings.read_only(self._config_bag.context) + del self._config_bag.properties def read_write(self): - """set configuration to read and write mode""" - settings = self.config_bag.context.cfgimpl_get_settings() - settings.read_write(self.config_bag.context) -# #FIXME ? + """Set config to read and write mode""" + settings = self._config_bag.context.cfgimpl_get_settings() + settings.read_write(self._config_bag.context) + #FIXME ? permissives = frozenset(settings.get_context_permissives() | frozenset(['hidden'])) settings.set_context_permissives(permissives) #/FIXME ? - del self.config_bag.properties + del self._config_bag.properties def add(self, prop): - """add a configuration property""" + """Add a config property""" props = self.get() props.add(prop) self.set(frozenset(props)) - del self.config_bag.properties + del self._config_bag.properties def pop(self, prop): - """remove a configuration property""" + """Remove a config property""" props = self.get() if prop in props: props.remove(prop) self.set(frozenset(props)) - del self.config_bag.properties + del self._config_bag.properties def get(self): - """get all configuration properties""" - return set(self.config_bag.properties) + """Get all config properties""" + return set(self._config_bag.properties) def set(self, props): - """personalise configuration properties""" - context = self.config_bag.context + """Personalise config properties""" + context = self._config_bag.context context.cfgimpl_get_settings().set_context_properties(props, context) - del self.config_bag.properties + del self._config_bag.properties def reset(self, all=False): - """remove configuration properties""" - context = self.config_bag.context + """Remove config properties""" + context = self._config_bag.context context.cfgimpl_get_settings().reset(None, context, all_properties=all) - del self.config_bag.properties + del self._config_bag.properties def exportation(self): - """export configuration properties""" - return self.config_bag.context.cfgimpl_get_settings()._p_.exportation() + """Export config properties""" + return self._config_bag.context.cfgimpl_get_settings()._p_.exportation() def importation(self, properties): - """import configuration properties""" - self.config_bag.context.cfgimpl_get_settings()._p_.importation(properties) - self.config_bag.context.cfgimpl_reset_cache(None, + """Import config properties""" + self._config_bag.context.cfgimpl_get_settings()._p_.importation(properties) + self._config_bag.context.cfgimpl_reset_cache(None, None) - del self.config_bag.properties + del self._config_bag.properties class TiramisuContextPermissive(TiramisuContext): - """manage configuration permissives""" + """Manage config permissives""" def get(self): - """get configuration permissives""" - return self.config_bag.context.cfgimpl_get_settings().get_context_permissives() + """Get config permissives""" + return self._config_bag.context.cfgimpl_get_settings().get_context_permissives() def set(self, permissives): - """set configuration permissives""" - self.config_bag.context.cfgimpl_get_settings().set_context_permissives(permissives) - del self.config_bag.permissives + """Set config permissives""" + self._config_bag.context.cfgimpl_get_settings().set_context_permissives(permissives) + del self._config_bag.permissives def exportation(self): - """export configuration permissives""" - return self.config_bag.context.cfgimpl_get_settings()._pp_.exportation() + """Export config permissives""" + return self._config_bag.context.cfgimpl_get_settings()._pp_.exportation() def importation(self, permissives): - """import configuration permissives""" - self.config_bag.context.cfgimpl_get_settings()._pp_.importation(permissives) - self.config_bag.context.cfgimpl_reset_cache(None, + """Import config permissives""" + self._config_bag.context.cfgimpl_get_settings()._pp_.importation(permissives) + self._config_bag.context.cfgimpl_reset_cache(None, None) - del self.config_bag.permissives - + del self._config_bag.permissives class TiramisuContextOption(TiramisuContext): - """manage option""" + + def _find(self, + name, + value, + type): + for path in self._config_bag.context.find(byname=name, + byvalue=value, + bytype=type, + config_bag=self._config_bag): + subconfig, name = self._config_bag.context.cfgimpl_get_home_by_path(path, + self._config_bag) + yield TiramisuOption(name, + path, + None, + subconfig, + self._config_bag) def find(self, name, value=undefined, - type=None, + type=None, first=False): - """find an option by name""" - if not first: - ret = [] - for path in self.config_bag.context.find(byname=name, - byvalue=value, - bytype=type, - #_subpath=self._path, - config_bag=self.config_bag): - subconfig, name = self.config_bag.context.cfgimpl_get_home_by_path(path, - self.config_bag) - t_option = TiramisuOption(name, - path, - None, # index for a slave ? - subconfig, - self.config_bag) - if first: - return t_option - ret.append(t_option) - return ret + """Find an or a list of options""" + if first: + return next(self._find(name, value, type)) + return self._find(name, value, type) def list(self, type='option', group_type=None, recursive=False): - """list content of an optiondescription""" + """List options (by default list only option)""" def _filter(opt): - if self.config_bag.properties: + if self._config_bag.properties: name = opt.impl_getname() option_bag = OptionBag() option_bag.set_option(opt, name, None, - self.config_bag) + self._config_bag) if opt.impl_is_optiondescription(): - self.config_bag.context.cfgimpl_get_settings().validate_properties(option_bag) + self._config_bag.context.cfgimpl_get_settings().validate_properties(option_bag) else: - self.config_bag.context.getattr(name, + self._config_bag.context.getattr(name, option_bag) def _walk(option): - for opt in option.impl_getchildren(self.config_bag): + for opt in option.impl_getchildren(self._config_bag): try: subsubconfig = _filter(opt) except PropertiesOptionError: @@ -951,116 +1019,123 @@ class TiramisuContextOption(TiramisuContext): elif type == 'optiondescription': continue path = opt.impl_getpath() - subconfig, name = self.config_bag.context.cfgimpl_get_home_by_path(path, - self.config_bag) + subconfig, name = self._config_bag.context.cfgimpl_get_home_by_path(path, + self._config_bag) yield TiramisuOption(name, path, None, subconfig, - self.config_bag) + self._config_bag) if type not in ('all', 'option', 'optiondescription'): raise APIError(_('unknown list type {}').format(type)) if group_type is not None and not isinstance(group_type, groups.GroupType): raise TypeError(_("unknown group_type: {0}").format(group_type)) - option = self.config_bag.context.cfgimpl_get_description() + option = self._config_bag.context.cfgimpl_get_description() for toption in _walk(option): yield toption -class TiramisuContextConfig(TiramisuContext): - """configuration methods""" - def find(self, - name: str, - value=undefined, - first: bool=False): - """find a path from option name and optionnaly a value to MetaConfig or GroupConfig""" - if first: - return Config(self.config_bag.context.find_firsts(byname=name, - byvalue=value, - config_bag=self.config_bag)) - else: # pragma: no cover - raise APIError('not implemented yet') - - def name(self): - return self.config_bag.context.impl_getname() - - def _c_copy(self, - session_id=None, - persistent=False, - storage=None): - return Config(self.config_bag.context.duplicate(session_id, - persistent=persistent, - storage=storage)) - - def _c_deepcopy(self, - session_id=None, - persistent=False, - storage=None, - metaconfig_prefix=None): - return Config(self.config_bag.context.duplicate(session_id, - persistent=persistent, - storage=storage, - metaconfig_prefix=metaconfig_prefix, - deep=True)) - - def _c_metaconfig(self): - return Config(self.config_bag.context.cfgimpl_get_meta()) - - def _m_new(self, - session_id, - persistent=False, - type='config'): - return Config(self.config_bag.context.new_config(session_id=session_id, - persistent=persistent, - type_=type)) - - def _m_pop(self, - session_id): - return Config(self.config_bag.context.pop_config(session_id=session_id)) - - def _m_list(self): - return self._g_list() - - def _g_list(self): - for child in self.config_bag.context.cfgimpl_get_children(): - yield Config(child) - - def _m_reset(self): - self._c_reset() - - def _c_reset(self): +class _TiramisuContextConfigReset(): + def reset(self): + """Remove all datas to current config (informations, values, properties, ...)""" # Option's values - context_owner = self.config_bag.context.cfgimpl_get_values().get_context_owner() - self.config_bag.context.cfgimpl_get_values()._p_.importation((tuple(), tuple(), tuple(), tuple())) - self.config_bag.context.cfgimpl_get_values()._p_.setvalue(None, + context_owner = self._config_bag.context.cfgimpl_get_values().get_context_owner() + self._config_bag.context.cfgimpl_get_values()._p_.importation((tuple(), tuple(), tuple(), tuple())) + self._config_bag.context.cfgimpl_get_values()._p_.setvalue(None, None, context_owner, None, True) # Option's informations - self.config_bag.context.cfgimpl_get_values()._p_.del_informations() + self._config_bag.context.cfgimpl_get_values()._p_.del_informations() # Option's properties - self.config_bag.context.cfgimpl_get_settings()._p_.importation({}) + self._config_bag.context.cfgimpl_get_settings()._p_.importation({}) # Option's permissives - self.config_bag.context.cfgimpl_get_settings()._pp_.importation({}) + self._config_bag.context.cfgimpl_get_settings()._pp_.importation({}) # Remove cache - self.config_bag.context.cfgimpl_reset_cache(None, None) + self._config_bag.context.cfgimpl_reset_cache(None, None) - def __getattr__(self, - name: str) -> Callable: - if not name.startswith('_'): - try: - if self.config_bag.context.impl_type == 'meta': - return getattr(self, '_m_' + name) - elif self.config_bag.context.impl_type == 'group': - return getattr(self, '_g_' + name) - elif self.config_bag.context.impl_type == 'config': - return getattr(self, '_c_' + name) - except APIError: # pragma: no cover - raise APIError(_('{} is unknown').format(name)) - raise APIError(_('{} is unknown').format(name)) # pragma: no cover + +class _TiramisuContextConfig(TiramisuContext, _TiramisuContextConfigReset): + """Actions to Config""" + def name(self): + return self._config_bag.context.impl_getname() + + def copy(self, + session_id=None, + persistent=False, + storage=None): + return Config(self._config_bag.context.duplicate(session_id, + persistent=persistent, + storage=storage)) + + def deepcopy(self, + session_id=None, + persistent=False, + storage=None, + metaconfig_prefix=None): + return Config(self._config_bag.context.duplicate(session_id, + persistent=persistent, + storage=storage, + metaconfig_prefix=metaconfig_prefix, + deep=True)) + + def metaconfig(self): + return Config(self._config_bag.context.cfgimpl_get_meta()) + + +class _TiramisuContextGroupConfig(TiramisuContext): + """Actions to GroupConfig""" + def name(self): + """Get config name""" + return self._config_bag.context.impl_getname() + + def list(self): + """List children's config""" + for child in self._config_bag.context.cfgimpl_get_children(): + yield Config(child) + + def find(self, + name: str, + value=undefined, + first: bool=False): + """Find an or a list of options""" + if first: + return Config(self._config_bag.context.find_firsts(byname=name, + byvalue=value, + config_bag=self._config_bag)) + else: + raise APIError('not implemented yet') + + def __call__(self, + path: Optional[str]): + """select a child Tiramisu config""" + if path is None: + return Config(self._config_bag) + spaths = path.split('.') + config = self._config_bag.context + for spath in spaths: + config = config.getconfig(spath) + return Config(config) + + +class _TiramisuContextMetaConfig(_TiramisuContextGroupConfig, _TiramisuContextConfigReset): + """Actions to MetaConfig""" + def new(self, + session_id, + persistent=False, + type='config'): + """Create and add a new config""" + return Config(self._config_bag.context.new_config(session_id=session_id, + persistent=persistent, + type_=type)) + + def pop(self, + session_id): + """Remove config from MetaConfig""" + return Config(self._config_bag.context.pop_config(session_id=session_id)) class TiramisuDispatcher: @@ -1068,16 +1143,16 @@ class TiramisuDispatcher: class TiramisuAPI(TiramisuHelp): - registers = {} + _registers = {} def __init__(self, config) -> None: if not isinstance(config, ConfigBag): config = ConfigBag(context=config) self._config_bag = config - if not self.registers: - registers(self.registers, 'TiramisuContext') - registers(self.registers, 'TiramisuDispatcher') + if not self._registers: + _registers(self._registers, 'TiramisuContext') + _registers(self._registers, 'TiramisuDispatcher') def __getattr__(self, subfunc: str) -> Any: if subfunc == 'forcepermissive': @@ -1088,47 +1163,48 @@ class TiramisuAPI(TiramisuHelp): config_bag = self._config_bag.copy() config_bag.properties = frozenset() return TiramisuAPI(config_bag) - elif subfunc in self.registers: + elif subfunc == 'config': + config_type = self._config_bag.context.impl_type + if config_type == 'group': + config = _TiramisuContextGroupConfig + elif config_type == 'meta': + config = _TiramisuContextMetaConfig + else: + config = _TiramisuContextConfig + return config(self._config_bag) + elif subfunc in self._registers: config_bag = self._config_bag del config_bag.permissives - return self.registers[subfunc](config_bag) + return self._registers[subfunc](config_bag) else: raise APIError(_('please specify a valid sub function ({})').format(subfunc)) - -class TiramisuDispatcherConfig(TiramisuDispatcher, TiramisuContextConfig): - def __call__(self, - path: Optional[str]): - """select a child Tiramisu configuration (only with MetaConfig or GroupConfig)""" - if path is None: - return Config(self.config_bag) - spaths = path.split('.') - config = self.config_bag.context - for spath in spaths: - config = config.getconfig(spath) - return Config(config) + def __dir__(self): + return list(self._registers.keys()) + ['unrestraint', 'forcepermissive', 'config'] class TiramisuDispatcherOption(TiramisuDispatcher, TiramisuContextOption): - subhelp = TiramisuOption + """Select an option""" def __call__(self, path: str, index: Optional[int]=None) -> TiramisuOption: - """select a option (index only for slave option)""" - if self.config_bag.context.impl_type == 'group': + """Select an option by path""" + if self._config_bag.context.impl_type == 'group': subpath, name = path.rsplit('.', 1) subconfig = None else: - subconfig, name = self.config_bag.context.cfgimpl_get_home_by_path(path, - self.config_bag) + subconfig, name = self._config_bag.context.cfgimpl_get_home_by_path(path, + self._config_bag) return TiramisuOption(name, path, index, subconfig, - self.config_bag) + self._config_bag) +#__________________________________________________________________________________________________ class Config(TiramisuAPI): + """Config to access to Option""" def __init__(self, descr: OptionDescription, session_id: str=None, @@ -1144,8 +1220,8 @@ class Config(TiramisuAPI): super().__init__(config) - class MetaConfig(TiramisuAPI): + """MetaConfig to access to Config""" def __init__(self, children, session_id: Union[str, None]=None, @@ -1167,6 +1243,7 @@ class MetaConfig(TiramisuAPI): class GroupConfig(TiramisuAPI): + """GroupConfig to access to Config""" def __init__(self, children, session_id: Union[str, None]=None) -> None: @@ -1177,12 +1254,3 @@ class GroupConfig(TiramisuAPI): config = KernelGroupConfig(_children, session_id=session_id) super().__init__(config) - - -def getapi(config: Config): # pragma: no cover - """instanciate Config - - :param config: KernelConfig object - :type descr: an instance of ``config.KernelConfig`` - """ - return config diff --git a/tiramisu/config.py b/tiramisu/config.py index 8af9eb2..ce85444 100644 --- a/tiramisu/config.py +++ b/tiramisu/config.py @@ -645,6 +645,9 @@ class _CommonConfig(SubConfig): def impl_del_information(self, key, raises=True): self._impl_values.del_information(key, raises) + def impl_list_information(self): + return self._impl_values.list_information() + def __getstate__(self): raise NotImplementedError() diff --git a/tiramisu/option/optiondescription.py b/tiramisu/option/optiondescription.py index 837036b..64a55ec 100644 --- a/tiramisu/option/optiondescription.py +++ b/tiramisu/option/optiondescription.py @@ -244,8 +244,6 @@ class OptionDescriptionWalk(CacheOptionDescription): subpath = None for child in self._children[1]: if dyn and child.impl_is_dynoptiondescription(): - if config_bag.context is None: # pragma: no cover - raise ConfigError(_('need context')) if subpath is None: if config_bag.context.cfgimpl_get_description() == self: subpath = '' diff --git a/tiramisu/storage/dictionary/value.py b/tiramisu/storage/dictionary/value.py index fa42f71..764be96 100644 --- a/tiramisu/storage/dictionary/value.py +++ b/tiramisu/storage/dictionary/value.py @@ -289,6 +289,12 @@ class Values(Cache): if raises: raise ValueError(_("information's item not found {0}").format(key)) + def list_information(self, path): + if path in self._informations: + return self._informations[path].keys() + else: + return [] + def del_informations(self): self._informations = {} diff --git a/tiramisu/storage/sqlite3/value.py b/tiramisu/storage/sqlite3/value.py index 4bebd3e..68678a2 100644 --- a/tiramisu/storage/sqlite3/value.py +++ b/tiramisu/storage/sqlite3/value.py @@ -228,6 +228,14 @@ class Values(Sqlite3DB): self._storage.execute("DELETE FROM information WHERE key = ? AND session_id = ? AND path = ?", (key, self._session_id, path)) + def list_information(self, path): + path = self._sqlite_encode_path(path) + rows = self._storage.select("SELECT key FROM information WHERE session_id = ? AND path = ?", + (self._session_id, path), + only_one=False) + for row in rows: + yield self._sqlite_decode_path(row[0]) + def del_informations(self): self._storage.execute("DELETE FROM information WHERE session_id = ?", (self._session_id,)) diff --git a/tiramisu/value.py b/tiramisu/value.py index dd72e98..df38516 100644 --- a/tiramisu/value.py +++ b/tiramisu/value.py @@ -513,6 +513,9 @@ class Values(object): def del_information(self, key, raises=True, path=None): self._p_.del_information(path, key, raises) + def list_information(self, path=None): + return self._p_.list_information(path) + #______________________________________________________________________ # mandatory warnings def _mandatory_warnings(self,