tiramisu/tiramisu/api.py

1107 lines
43 KiB
Python

# -*- coding: utf-8 -*-
# Copyright (C) 2017-2018 Team tiramisu (see AUTHORS for all contributors)
#
# This program is free software: you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# ____________________________________________________________
from inspect import ismethod, getdoc, signature
from time import time
from copy import deepcopy
from typing import List, Any, Optional, Callable, Union, Dict
from .error import APIError, ConfigError, SlaveError, PropertiesOptionError
from .i18n import _
from .setting import ConfigBag, OptionBag, owners, groups, Undefined, undefined, FORBIDDEN_SET_PROPERTIES
from .config import KernelConfig, SubConfig, KernelGroupConfig, KernelMetaConfig
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'
def help(self,
init: bool=True,
space: str="",
root: str='',
_display: bool=True,
_valid: bool=False) -> List[str]:
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)))
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
class CommonTiramisu(TiramisuHelp):
allow_optiondescription = True
registers = {}
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)
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)
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():
raise APIError(_('option must not be an optiondescription'))
return option
class CommonTiramisuOption(CommonTiramisu):
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._name = name
self.subconfig = subconfig
if option_bag is not None:
# for help()
self._get_option()
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
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))
def __getattr__(self, name):
if not hasattr(CommonTiramisuOption, name):
raise APIError(_('unknown method {}').format(name))
else:
super().__getattribute__(name)
class TiramisuOptionOption(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()
def ismasterslaves(self):
"""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
return option.impl_get_display_name()
def name(self):
"""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()
def has_dependency(self, self_is_dep=True):
"""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
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))
def isoptiondescription(self):
"""test if option is an optiondescription"""
option = self.option_bag.option
return option.impl_is_optiondescription()
class TiramisuOptionOwner(CommonTiramisuOption):
"""manager option's owner"""
def __init__(self,
name: str,
subconfig: Union[KernelConfig, SubConfig],
option_bag: OptionBag) -> None:
super().__init__(name,
subconfig,
option_bag)
if option_bag is not None:
# for help()
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)
def isdefault(self):
"""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
try:
obj_owner = getattr(owners, owner)
except AttributeError:
owners.addowner(owner)
obj_owner = getattr(owners, owner)
self.values.setowner(obj_owner,
self.option_bag)
class TiramisuOptionProperty(CommonTiramisuOption):
"""manager option's property"""
allow_optiondescription = True
slave_need_index = False
def __init__(self,
name: str,
subconfig: Union[KernelConfig, SubConfig],
option_bag: OptionBag) -> None:
super().__init__(name,
subconfig,
option_bag)
if option_bag and option_bag.config_bag:
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
if apply_requires:
self._test_slave_index()
else:
self.option_bag.apply_requires = False
properties = self.option_bag.properties
return set(properties)
def add(self, prop):
"""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,
apply_requires=False)
self.settings.setproperties(self.option_bag.path,
props | {prop},
self.option_bag)
def pop(self, prop):
"""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,
props - {prop},
self.option_bag)
def reset(self):
"""reset all personalised properties"""
option = self.option_bag.option
self.settings.reset(self.option_bag)
class TiramisuOptionPermissive(CommonTiramisuOption):
"""manager option's property"""
allow_optiondescription = True
slave_need_index = False
# FIXME should have same api than property
def __init__(self,
name: str,
subconfig: Union[KernelConfig, SubConfig],
option_bag: OptionBag) -> None:
super().__init__(name,
subconfig,
option_bag)
if option_bag and option_bag.config_bag:
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)
def set(self, permissives):
"""set permissives value"""
option = self.option_bag.option
self.settings.setpermissives(self.option_bag,
permissives=permissives)
def reset(self):
"""reset all personalised permissive"""
self.set(frozenset())
class TiramisuOptionInformation(CommonTiramisuOption):
"""manage option informations"""
allow_optiondescription = True
slave_need_index = False
def get(self, name, default=undefined):
"""get information for a key name"""
option = self.option_bag.option
return option.impl_get_information(name, default)
def set(self, name, value):
"""set information for a key name"""
#FIXME ?
self.config_bag.context.impl_set_information(name, value)
def reset(self, name):
"""remove information for a key name"""
#FIXME ?
self.config_bag.context.impl_del_information(name)
class TiramisuOptionValue(CommonTiramisuOption):
"""manager option's value"""
slave_need_index = False
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)
def set(self, value):
"""set a value for a specified option"""
option = self.option_bag.option
self._test_slave_index()
values = self.option_bag.config_bag.context.cfgimpl_get_values()
if isinstance(value, list):
while undefined in value:
idx = value.index(undefined)
option_bag = OptionBag()
option_bag.set_option(self.option_bag.option,
self.option_bag.path,
idx,
self.option_bag.config_bag)
value[idx] = values.getdefaultvalue(option_bag)
else:
if value == undefined:
value = values.getdefaultvalue(self.option_bag)
self.subconfig.setattr(value,
self.option_bag)
def _pop(self, index):
"""pop value for a master option (only for master option)"""
if self.option_bag.option.impl_is_symlinkoption():
raise TypeError(_("can't delete a SymLinkOption"))
self.option_bag.config_bag.context.cfgimpl_get_values().reset_master(index,
self.option_bag,
self.subconfig)
def reset(self):
"""reset value for a value"""
self._test_slave_index()
self.subconfig.delattr(self.option_bag)
def _len_master(self):
"""length of master 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()
return self._length
def _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 __getattr__(self, name: str) -> Callable:
option = self.option_bag.option
if name == 'list' and isinstance(option, ChoiceOption):
return self._list
elif name == 'pop' and option.impl_is_master_slaves('master'):
return self._pop
elif name == 'len':
if option.impl_is_master_slaves('slave'):
return self._len_slave
if option.impl_is_master_slaves('master'):
return self._len_master
raise APIError(_('{} is unknown').format(name))
def _list(self):
"""all values available for an option (only for choiceoption)"""
option = self.option_bag.option
return option.impl_get_values(self.option_bag)
def registers(registers: Dict[str, type], prefix: str) -> 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
class TiramisuOption(CommonTiramisu):
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:
self._name = name
self.subconfig = subconfig
self._path = path
self.index = index
self.config_bag = config_bag
if option_bag:
self.option_bag = option_bag
else:
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__)
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)
raise APIError(_('please specify a valid sub function ({})').format(subfunc))
def dict(self,
flatten=False,
withvalue=undefined,
withoption=None,
fullpath=False):
"""return dict with path as key and value (only for optiondescription)"""
self._get_option()
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'}
return config_bag.context.get_subconfig(self._path,
self.option_bag).make_dict(config_bag=config_bag,
flatten=flatten,
fullpath=fullpath,
withoption=withoption,
withvalue=withvalue)
def _find(self,
name: str,
value=undefined,
type=None,
first: bool=False):
"""find an option by name (only for optiondescription)"""
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
def _get(self, name):
self._get_option()
current_option = self.option_bag.option.impl_getchild(name,
self.config_bag,
self.subconfig)
path = self.option_bag.path + '.' + name
option_bag= OptionBag()
option_bag.set_option(current_option,
path,
None,
self.config_bag)
if current_option.impl_is_optiondescription():
subconfig = self.subconfig.getattr(name,
option_bag)
else:
subconfig = self.subconfig
return TiramisuOption(name,
path,
None,
subconfig,
self.config_bag,
option_bag)
def _group_type(self):
"""get type for an optiondescription (only for optiondescription)"""
return self._get_option().impl_get_group_type()
def _list(self,
type='all',
group_type=None):
"""list options in an optiondescription (only for optiondescription)"""
if type not in ('all', '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))
def _filter(opt):
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)
if opt.impl_is_optiondescription():
self.subconfig.get_subconfig(name,
option_bag)
else:
self.subconfig.getattr(name,
option_bag)
option = self._get_option()
name = option.impl_getname()
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):
try:
subsubconfig = _filter(opt)
except PropertiesOptionError:
continue
if opt.impl_is_optiondescription():
if type == 'optiondescription' and \
(group_type and opt.impl_get_group_type() != group_type):
continue
else:
if type == 'optiondescription':
continue
name = opt.impl_getname()
yield TiramisuOption(name,
subconfig._get_subpath(name),
None,
subconfig,
self.config_bag)
class TiramisuContext(TiramisuHelp):
def __init__(self,
config_bag: Optional[ConfigBag]) -> None:
self.config_bag = config_bag
class TiramisuContextInformation(TiramisuContext):
"""manage configuration informations"""
def get(self, name, default=undefined):
"""get information for a key name"""
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)
def reset(self, name):
"""remove information for a key name"""
self.config_bag.context.impl_del_information(name)
class TiramisuContextValue(TiramisuContext):
"""manager 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)
def set(self,
path: str,
value,
index=None,
only_config=undefined,
force_default=undefined,
force_default_if_same=undefined,
force_dont_change_value=undefined):
"""set values for a GroupConfig or a MetaConfig"""
kwargs = {}
if only_config is not undefined:
kwargs['only_config'] = only_config
if force_default is not undefined:
kwargs['force_default'] = force_default
if force_default_if_same is not undefined:
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,
index,
value,
self.config_bag,
**kwargs)
def reset(self,
path):
"""reset value for a GroupConfig or a MetaConfig"""
self.config_bag.context.reset(path,
self.config_bag)
def exportation(self):
"""export all values"""
return self.config_bag.context.cfgimpl_get_values()._p_.exportation()
def importation(self, values):
"""import values"""
self.config_bag.context.cfgimpl_get_values()._p_.importation(values)
self.config_bag.context.cfgimpl_reset_cache(None, None)
class TiramisuContextOwner(TiramisuContext):
"""manager value"""
def get(self):
"""get default owner"""
return self.config_bag.context.cfgimpl_get_settings().getowner()
def set(self, owner):
"""set default owner"""
try:
obj_owner = getattr(owners, owner)
except AttributeError:
owners.addowner(owner)
obj_owner = getattr(owners, owner)
self.config_bag.context.cfgimpl_get_settings().setowner(obj_owner)
class TiramisuContextProperty(TiramisuContext):
"""manage configuration properties"""
def read_only(self):
"""set configuration to read only mode"""
settings = self.config_bag.context.cfgimpl_get_settings()
settings.read_only()
try:
del self.config_bag.properties
except AttributeError:
pass
def read_write(self):
"""set configuration to read and write mode"""
settings = self.config_bag.context.cfgimpl_get_settings()
settings.read_write()
# #FIXME ?
permissives = frozenset(settings.get_context_permissives() | frozenset(['hidden']))
settings.set_context_permissives(permissives)
try:
del self.config_bag.properties
except AttributeError:
pass
#/FIXME ?
def add(self, prop):
"""add a configuration property"""
props = self.get()
props.add(prop)
self.set(frozenset(props))
def pop(self, prop):
"""remove a configuration property"""
props = self.get()
if prop in props:
props.remove(prop)
self.set(frozenset(props))
def get(self):
"""get all configuration properties"""
return set(self.config_bag.properties)
def set(self, props):
"""personalise configuration properties"""
self.config_bag.context.cfgimpl_get_settings().set_context_properties(props)
def reset(self):
"""remove configuration properties"""
self.config_bag.context.cfgimpl_get_settings().reset(None)
def exportation(self):
"""export configuration 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,
None)
class TiramisuContextPermissive(TiramisuContext):
"""manage configuration permissives"""
def get(self):
"""get configuration 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)
def exportation(self):
"""export configuration 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,
None)
class TiramisuContextOption(TiramisuContext):
"""manage option"""
def find(self,
name,
value=undefined,
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
def get(self, name):
option = self.config_bag.context.cfgimpl_get_description().impl_getchild(name,
self.config_bag,
self.config_bag.context)
return TiramisuOption(name,
name,
None,
self.config_bag.context,
self.config_bag)
def list(self,
type='all',
group_type=None,
recursive=False):
"""list content of an optiondescription"""
def _filter(opt):
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.context.getattr(name,
option_bag)
if type not in ('all', '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))
if recursive:
if group_type:
raise APIError(_('recursive with group_type is not implemented yet'))
if self.config_bag.properties:
raise APIError(_('not implemented yet'))
for option in self.config_bag.context.cfgimpl_get_description()._cache_paths[1]:
if type == 'optiondescription' and not isinstance(option, OptionDescription):
continue
yield option
else:
option = self.config_bag.context.cfgimpl_get_description()
for opt in option.impl_getchildren(self.config_bag):
try:
subsubconfig = _filter(opt)
except PropertiesOptionError:
continue
if opt.impl_is_optiondescription():
if type == 'optiondescription' and \
(group_type and opt.impl_get_group_type() != group_type):
continue
else:
if type == 'optiondescription':
continue
name = opt.impl_getname()
yield TiramisuOption(name,
self.config_bag.context._get_subpath(name),
None,
self.config_bag.context,
self.config_bag)
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 TiramisuAPI(self.config_bag.context.find_firsts(byname=name,
byvalue=value,
config_bag=self.config_bag))
else:
raise APIError('not implemented yet')
def name(self):
return self.config_bag.context.impl_getname()
def duplicate(self,
session_id=None):
return TiramisuAPI(self.config_bag.context.duplicate(session_id))
def _m_new(self, name):
return TiramisuAPI(self.config_bag.context.new_config(name))
def _m_list(self):
return self._g_list()
def _g_list(self):
for child in self.config_bag.context.cfgimpl_get_children():
yield TiramisuAPI(child)
def __getattr__(self,
name: str) -> Callable:
if not name.startswith('_'):
try:
if isinstance(self.config_bag.context, KernelMetaConfig):
return getattr(self, '_m_' + name)
elif isinstance(self.config_bag.context, KernelGroupConfig):
return getattr(self, '_g_' + name)
except APIError:
raise APIError(_('{} is unknown').format(name))
raise APIError(_('{} is unknown').format(name))
def dict(self,
flatten=False,
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
else:
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,
withoption=withoption,
withvalue=withvalue)
class TiramisuDispatcher:
pass
class TiramisuAPI(TiramisuHelp):
registers = {}
def __init__(self,
config) -> None:
self._config = config
if not self.registers:
registers(self.registers, 'TiramisuContext')
registers(self.registers, 'TiramisuDispatcher')
def __getattr__(self, subfunc: str) -> Any:
if subfunc == 'forcepermissive':
if isinstance(self._config, ConfigBag):
config = self._config.config
force = not self._config.properties
else:
config = self._config
force = None
config_bag = ConfigBag(context=config)
config_bag.set_permissive()
if force is True:
config_bag.properties = frozenset()
return TiramisuAPI(config_bag)
elif subfunc == 'unrestraint':
#if isinstance(self._config, ConfigBag):
# config = self._config.context
# force = self._config.force_permissive
#else:
config = self._config
#force = None
config_bag = ConfigBag(context=config)
config_bag.properties = frozenset()
#if force is not None:
#config_bag.force_permissive = force
return TiramisuAPI(config_bag)
elif subfunc in self.registers:
if not isinstance(self._config, ConfigBag):
config_bag = ConfigBag(context=self._config)
else:
config_bag = self._config
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 TiramisuAPI(self.config_bag)
spaths = path.split('.')
config = self.config_bag.context
for spath in spaths:
config = config.getconfig(spath)
config_bag = self.config_bag.copy()
config_bag.context = config
return TiramisuAPI(config_bag)
class TiramisuDispatcherOption(TiramisuDispatcher, TiramisuContextOption):
subhelp = TiramisuOption
def __call__(self,
path: str,
index: Optional[int]=None) -> TiramisuOption:
"""select a option (index only for slave option)"""
subconfig, name = self.config_bag.context.cfgimpl_get_home_by_path(path,
self.config_bag)
return TiramisuOption(name,
path,
index,
subconfig,
self.config_bag)
class Config(TiramisuAPI):
def __init__(self,
descr: OptionDescription,
session_id: str=None,
persistent: bool=False,
storage=None) -> None:
if not isinstance(descr, KernelConfig):
config = KernelConfig(descr,
session_id=session_id,
persistent=persistent,
storage=storage)
else:
config = descr
super().__init__(config)
class MetaConfig(TiramisuAPI):
def __init__(self,
children,
session_id: Union[str, None]=None,
persistent: bool=False,
optiondescription: Union[OptionDescription, None]=None) -> None:
_children = []
for child in children:
if isinstance(child, TiramisuAPI):
_children.append(child._config)
else:
_children.append(child)
config = KernelMetaConfig(_children,
session_id=session_id,
persistent=persistent,
optiondescription=optiondescription)
super().__init__(config)
class GroupConfig(TiramisuAPI):
def __init__(self,
children,
session_id: Union[str, None]=None,
persistent: bool=False,
storage=None) -> None:
_children = []
for child in children:
_children.append(child._config)
config = KernelGroupConfig(_children,
session_id=session_id,
persistent=persistent,
storage=storage)
super().__init__(config)
def getapi(config: Config):
"""instanciate Config
:param config: KernelConfig object
:type descr: an instance of ``config.KernelConfig``
"""
return config