tiramisu/tiramisu/api.py
2018-08-01 19:13:42 +02:00

1150 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 Config, SubConfig, GroupConfig, MetaConfig
from .option import ChoiceOption
TIRAMISU_VERSION = 3
#try:
# from .value import Multi
#except:
# Multi = list
COUNT_TIME = False
#COUNT_TIME = {}
EXCLUDE_HELP = ('help', '_get_option', '_test_slave_index')
def count(func):
global MOD_COUNT_TIME
class_name = func.__str__().split()[1].split('.')[0]
func_name = func.__name__
def wrapper(*args, **kwargs): # pragma: no cover
time1 = time()
ret = func(*args, **kwargs)
time2 = time()
diff = (time2 - time1) * 1000.0
MOD_COUNT_TIME[class_name][func_name]['max'] = max(MOD_COUNT_TIME[class_name][func_name]['max'], diff)
MOD_COUNT_TIME[class_name][func_name]['min'] = min(MOD_COUNT_TIME[class_name][func_name]['min'], diff)
MOD_COUNT_TIME[class_name][func_name]['total'] += diff
MOD_COUNT_TIME[class_name][func_name]['nb'] += 1
#print('%s function took %0.3f ms' % (func_name, diff))
#print(COUNT_TIME)
return ret
if COUNT_TIME is not False: # pragma: no cover
COUNT_TIME.setdefault(class_name, {})
COUNT_TIME[class_name][func_name] = {'max': 0,
'min': 1000,
'nb': 0,
'total': 0}
MOD_COUNT_TIME = deepcopy(COUNT_TIME)
return wrapper
return func
def display_count():
if COUNT_TIME is not False: # pragma: no cover
global MOD_COUNT_TIME
#print(MOD_COUNT_TIME)
print()
for class_name in MOD_COUNT_TIME:
print('>', class_name)
for func in MOD_COUNT_TIME[class_name]:
print('=>', func)
print('==> nb:', MOD_COUNT_TIME[class_name][func]['nb'])
if MOD_COUNT_TIME[class_name][func]['nb'] != 0:
print('==> min:', MOD_COUNT_TIME[class_name][func]['min'])
print('==> max:', MOD_COUNT_TIME[class_name][func]['max'])
print('==> moy:', MOD_COUNT_TIME[class_name][func]['total'] / MOD_COUNT_TIME[class_name][func]['nb'])
MOD_COUNT_TIME = deepcopy(COUNT_TIME)
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]
instance_module = module(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.config_bag,
self.subconfig)
self.option_bag.set_option(option,
self._path,
self.index,
self.config_bag)
if self.config_bag.setting_properties:
self.config_bag.config.cfgimpl_get_settings().validate_properties(self.option_bag)
if self.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 self.index >= self._length:
raise SlaveError(_('index "{}" is higher than the master length "{}" '
'for option "{}"').format(self.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,
path: str,
index: int,
subconfig: Union[Config, SubConfig],
config_bag: ConfigBag,
option_bag: OptionBag) -> None:
self._path = path
self.index = index
self.config_bag = config_bag
self.option_bag = option_bag
self._name = name
self.subconfig = subconfig
if config_bag is not None and self.slave_need_index:
self._test_slave_index()
def _test_slave_index(self) -> None:
option = self._get_option()
if not option.impl_is_optiondescription():
if self.index is None and option.impl_is_master_slaves('slave'):
raise APIError('index must be set with a slave option')
elif self.index is not None and not option.impl_is_master_slaves('slave'):
raise APIError('index must be set only with a slave option')
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
@count
def get(self):
"""get Tiramisu option"""
return self._get_option()
@count
def _ismulti(self):
"""test if option could have multi value"""
option = self._get_option()
return option.impl_is_multi()
@count
def _issubmulti(self):
"""test if option could have submulti value"""
option = self._get_option()
return option.impl_is_submulti()
@count
def ismasterslaves(self):
"""test if option is a master or a slave"""
option = self._get_option()
return option.impl_is_master_slaves()
@count
def _ismaster(self):
"""test if option is a master"""
option = self._get_option()
return option.impl_is_master_slaves('master')
@count
def _isslave(self):
"""test if option is a slave"""
option = self._get_option()
return option.impl_is_master_slaves('slave')
@count
def doc(self):
"""get option document"""
option = self._get_option()
return option.impl_get_display_name()
@count
def name(self):
"""get option name"""
self._get_option()
return self._name
def path(self) -> str:
"""get option path"""
self._get_option()
return self._path
@count
def _default(self):
"""get default value for an option (not for optiondescription)"""
option = self._get_option()
return option.impl_getdefault()
@count
def _defaultmulti(self):
"""get default value when added a value for a multi option (not for optiondescription)"""
option = self._get_option()
return option.impl_getdefault_multi()
@count
def has_dependency(self, self_is_dep=True):
"""test if option has dependency"""
option = self._get_option()
return option.impl_has_dependency(self_is_dep)
@count
def _consistencies(self):
"""get consistencies for an option (not for optiondescription)"""
option = self._get_option()
return option.get_consistencies()
@count
def _callbacks(self):
"""get callbacks for an option (not for optiondescription)"""
option = self._get_option()
return option.impl_get_callback()
@count
def requires(self):
"""get requires for an option"""
option = self._get_option()
return option.impl_getrequires()
def __getattr__(self, name: str) -> Callable:
#if not self._get_option().impl_is_optiondescription() and name != 'get_option':
if not self._get_option().impl_is_optiondescription():
subkey = '_' + name
if subkey in dir(self):
func = getattr(self, subkey)
if callable(func):
return func
raise APIError(_('{} is unknown').format(name))
def isoptiondescription(self):
"""test if option is an optiondescription"""
return self._get_option().impl_is_optiondescription()
class TiramisuOptionOwner(CommonTiramisuOption):
"""manager option's owner"""
def __init__(self,
name: str,
path: str,
index: int,
subconfig: Union[Config, SubConfig],
config_bag: ConfigBag,
option_bag: OptionBag) -> None:
super().__init__(name,
path,
index,
subconfig,
config_bag,
option_bag)
if config_bag:
self.values = self.config_bag.config.cfgimpl_get_values()
@count
def get(self):
"""get owner for a specified option"""
option = self._get_option()
return self.values.getowner(self.option_bag)
@count
def isdefault(self):
"""is option has defaut value"""
self._get_option()
return self.values.is_default_owner(self.option_bag)
@count
def set(self, owner):
"""get owner for a specified option"""
self._get_option()
if TIRAMISU_VERSION == 2:
if owner in ['default', 'forced', 'meta']:
raise ConfigError()
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,
path: str,
index: int,
subconfig: Union[Config, SubConfig],
config_bag: ConfigBag,
option_bag: OptionBag) -> None:
super().__init__(name,
path,
index,
subconfig,
config_bag,
option_bag)
if config_bag:
self.settings = config_bag.config.cfgimpl_get_settings()
@count
def get(self, apply_requires=True):
"""get properties for an option"""
self._get_option()
if apply_requires:
self._test_slave_index()
else:
self.option_bag.apply_requires = False
properties = self.option_bag.properties
return set(properties)
@count
def add(self, prop):
"""add new property for an option"""
self._get_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._path,
props | {prop},
self.option_bag)
@count
def pop(self, prop):
"""remove new property for an option"""
self._get_option()
props = self.settings.getproperties(self.option_bag,
apply_requires=False)
self.settings.setproperties(self._path,
props - {prop},
self.option_bag)
@count
def reset(self):
"""reset all personalised properties"""
self._get_option()
self.settings.reset(self.option_bag)
class TiramisuOptionPermissive(CommonTiramisuOption):
"""manager option's property"""
allow_optiondescription = True
slave_need_index = False
def __init__(self,
name: str,
path: str,
index: int,
subconfig: Union[Config, SubConfig],
config_bag: ConfigBag,
option_bag: OptionBag) -> None:
super().__init__(name,
path,
index,
subconfig,
config_bag,
option_bag)
if config_bag:
self.settings = config_bag.config.cfgimpl_get_settings()
@count
def get(self):
"""get permissives value"""
if TIRAMISU_VERSION == 2:
args = [self.setting_properties, self._path]
else:
args = [self._get_option(), self._path]
return self.settings.getpermissive(*args)
@count
def set(self, permissives):
"""set permissives value"""
self._get_option()
self.settings.setpermissive(self.option_bag,
permissives=permissives)
@count
def reset(self):
"""reset all personalised permissive"""
self.set(frozenset())
class TiramisuOptionInformation(CommonTiramisuOption):
"""manage option informations"""
allow_optiondescription = True
slave_need_index = False
@count
def get(self, name, default=undefined):
"""get information for a key name"""
option = self._get_option()
return option.impl_get_information(name, default)
@count
def set(self, name, value):
"""set information for a key name"""
self.config_bag.config.impl_set_information(name, value)
@count
def reset(self, name):
"""remove information for a key name"""
self.config_bag.config.impl_del_information(name)
class TiramisuOptionValue(CommonTiramisuOption):
"""manager option's value"""
slave_need_index = False
@count
def get(self):
"""get option's value"""
self._test_slave_index()
settings = self.config_bag.config.cfgimpl_get_settings()
value = self.subconfig.getattr(self._name,
self.option_bag)
#if isinstance(value, Multi):
# value = list(value)
return value
@count
def set(self, value):
"""set a value for a specified option"""
self._get_option()
self._test_slave_index()
values = self.config_bag.config.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.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)
@count
def _pop(self, index):
"""pop value for a master option (only for master option)"""
self._get_option()
if self.option_bag.option.impl_is_symlinkoption():
raise TypeError(_("can't delete a SymLinkOption"))
self.config_bag.config.cfgimpl_get_values().reset_master(index,
self.option_bag,
self.subconfig)
@count
def reset(self):
"""reset value for a value"""
self._get_option()
self._test_slave_index()
#self.config_bag.config.delattr(self.option_bag)
self.subconfig.delattr(self.option_bag)
@count
def _len_master(self):
"""length of master option (only for slave option)"""
option = self._get_option()
# for example if index is None
if '_length' not in vars(self):
self._length = self.subconfig.cfgimpl_get_length()
return self._length
@count
def _len_slave(self):
"""length of slave option (only for slave option)"""
option = self._get_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:
if name == 'list' and isinstance(self._get_option(), ChoiceOption):
return self._list
elif name == 'pop' and self._get_option().impl_is_master_slaves('master'):
return self._pop
elif name == 'len':
if self._get_option().impl_is_master_slaves('slave'):
return self._len_slave
if self._get_option().impl_is_master_slaves('master'):
return self._len_master
raise APIError(_('{} is unknown').format(name))
@count
def _list(self):
"""all values available for an option (only for choiceoption)"""
self._get_option()
return self._get_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, Config, 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()
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._path,
self.index,
self.subconfig,
self.config_bag,
self.option_bag)
elif subfunc == 'make_dict' and self._get_option().impl_is_optiondescription():
return self._make_dict
elif subfunc == 'find' and self._get_option().impl_is_optiondescription():
return self._find
elif subfunc == 'get' and self._get_option().impl_is_optiondescription():
return self._get
elif subfunc == 'list' and self._get_option().impl_is_optiondescription():
return self._list
elif subfunc == 'group_type' and self._get_option().impl_is_optiondescription():
return self._group_type
else:
raise APIError(_('please specify a valid sub function ({})').format(subfunc))
@count
def _make_dict(self,
flatten=False,
withvalue=undefined,
withoption=None,
fullpath=False):
"""return dict with path as key and value for an optiondescription (only for optiondescription)"""
self._get_option()
return self.config_bag.config.getattr(self._path,
self.option_bag).make_dict(config_bag=self.config_bag,
flatten=flatten,
fullpath=fullpath,
withoption=withoption,
withvalue=withvalue)
def _find(self,
name: str,
value: Union[bool, Undefined]=undefined,
type=None,
first: bool=False):
"""find an option by name (only for optiondescription)"""
if not first:
ret = []
for path in self.config_bag.config.find(byname=name,
byvalue=value,
bytype=type,
_subpath=self._path,
config_bag=self.config_bag):
subconfig, name = self.config_bag.config.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
@count
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)
@count
def _group_type(self):
"""get type for an optiondescription (only for optiondescription)"""
return self._get_option().impl_get_group_type()
@count
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 not self.config_bag.force_unrestraint:
name = opt.impl_getname()
path = subconfig._get_subpath(name)
option_bag = OptionBag()
option_bag.set_option(opt,
path,
None,
self.config_bag)
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.getattr(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"""
@count
def get(self, name, default=undefined):
"""get information for a key name"""
return self.config_bag.config.impl_get_information(name, default)
@count
def set(self, name, value):
"""set information for a key name"""
self.config_bag.config.impl_set_information(name, value)
@count
def reset(self, name):
"""remove information for a key name"""
self.config_bag.config.impl_del_information(name)
class TiramisuContextValue(TiramisuContext):
"""manager value"""
@count
def mandatory_warnings(self):
"""return path of options with mandatory property without any value"""
return self.config_bag.config.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.config.set_value(path,
index,
value,
self.config_bag,
**kwargs)
@count
def reset(self,
path):
"""reset value for a GroupConfig or a MetaConfig"""
self.config_bag.config.reset(path,
self.config_bag)
@count
def exportation(self):
"""export all values"""
return self.config_bag.config.cfgimpl_get_values()._p_.exportation()
@count
def importation(self, values):
"""import values"""
self.config_bag.config.cfgimpl_get_values()._p_.importation(values)
self.config_bag.config.cfgimpl_reset_cache(None, None)
class TiramisuContextOwner(TiramisuContext):
"""manager value"""
@count
def get(self):
"""get default owner"""
return self.config_bag.config.cfgimpl_get_settings().getowner()
@count
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.config.cfgimpl_get_settings().setowner(obj_owner)
class TiramisuContextProperty(TiramisuContext):
"""manage configuration properties"""
@count
def read_only(self):
"""set configuration to read only mode"""
settings = self.config_bag.config.cfgimpl_get_settings()
settings.read_only()
try:
del self.config_bag.setting_properties
except AttributeError:
pass
@count
def read_write(self):
"""set configuration to read and write mode"""
settings = self.config_bag.config.cfgimpl_get_settings()
settings.read_write()
# #FIXME ?
settings.set_context_permissive(frozenset(['hidden']))
try:
del self.config_bag.setting_properties
except AttributeError:
pass
#/FIXME ?
@count
def add(self, prop):
"""add a configuration property"""
props = self.get()
props.add(prop)
self.set(frozenset(props))
@count
def pop(self, prop):
"""remove a configuration property"""
props = self.get()
if prop in props:
props.remove(prop)
self.set(frozenset(props))
@count
def get(self):
"""get all configuration properties"""
return set(self.config_bag.setting_properties)
@count
def set(self, props):
"""personalise configuration properties"""
self.config_bag.config.cfgimpl_get_settings().set_context_properties(props)
@count
def reset(self):
"""remove configuration properties"""
self.config_bag.config.cfgimpl_get_settings().reset(None)
@count
def exportation(self):
"""export configuration properties"""
return self.config_bag.config.cfgimpl_get_settings()._p_.exportation()
@count
def importation(self, properties):
"""import configuration properties"""
self.config_bag.config.cfgimpl_get_settings()._p_.importation(properties)
self.config_bag.config.cfgimpl_reset_cache(None,
None)
class TiramisuContextPermissive(TiramisuContext):
"""manage configuration permissives"""
@count
def get(self):
"""get configuration permissives"""
return self.config_bag.config.cfgimpl_get_settings().get_context_permissive()
@count
def set(self, permissives):
"""set configuration permissives"""
self.config_bag.config.cfgimpl_get_settings().set_context_permissive(permissives)
@count
def exportation(self):
"""export configuration permissives"""
return self.config_bag.config.cfgimpl_get_settings()._pp_.exportation()
@count
def importation(self, permissives):
"""import configuration permissives"""
self.config_bag.config.cfgimpl_get_settings()._pp_.importation(permissives)
self.config_bag.config.cfgimpl_reset_cache(None,
None)
class TiramisuContextOption(TiramisuContext):
"""manage option"""
@count
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.config.find(byname=name,
byvalue=value,
bytype=type,
#_subpath=self._path,
config_bag=self.config_bag):
subconfig, name = self.config_bag.config.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
@count
def get(self, name):
option = self.config_bag.config.cfgimpl_get_description().impl_getchild(name,
self.config_bag,
self.config_bag.config)
return TiramisuOption(name,
name,
None,
self.config_bag.config,
self.config_bag)
@count
def make_dict(self,
flatten=False,
withvalue=undefined,
withoption=None,
fullpath=False):
"""return dict with path as key and value"""
return self.config_bag.config.make_dict(self.config_bag,
flatten=flatten,
fullpath=fullpath,
withoption=withoption,
withvalue=withvalue)
@count
def list(self,
type='all',
group_type=None,
recursive=False):
"""list content of an optiondescription"""
# FIXME should return TiramisuOption !!!
if group_type is not None and not isinstance(group_type,
groups.GroupType):
raise TypeError(_("unknown group_type: {0}").format(group_type))
if type == 'optiondescription':
if recursive:
raise APIError(_('not implemented yet'))
else:
if not self.config_bag.force_unrestraint:
option = self.config_bag.config.cfgimpl_get_description()
for opt in option.impl_getchildren(self.config_bag):
if type == 'optiondescription' and not opt.impl_is_optiondescription():
continue
yield opt.impl_getname()
else:
# FIXME itergroups !!!
return self.config_bag.config.iter_groups(self.config_bag, group_type)
elif type == 'all':
if group_type:
raise APIError(_('not implemented yet'))
if recursive:
if not self.config_bag.force_unrestraint:
raise APIError(_('not implemented yet'))
else:
return self.config_bag.config.cfgimpl_get_description()._cache_paths[1]
else:
return self.config_bag.config.cfgimpl_get_children(self.config_bag)
else:
raise APIError(_('unknown list type {}').format(type))
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 self.config_bag.config.find_firsts(byname=name,
byvalue=value,
config_bag=self.config_bag)
else:
raise APIError('not implemented yet')
class TiramisuDispatcher:
pass
class TiramisuAPI(TiramisuHelp):
registers = {}
def __init__(self,
config: Union[Config, GroupConfig, MetaConfig, ConfigBag]) -> 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 = self._config.force_unrestraint
else:
config = self._config
force = None
config_bag = ConfigBag(config=config,
force_permissive=True)
if force is not None:
config_bag.force_unrestraint = force
return TiramisuAPI(config_bag)
elif subfunc == 'unrestraint':
if isinstance(self._config, ConfigBag):
config = self._config.config
force = self._config.force_permissive
else:
config = self._config
force = None
config_bag = ConfigBag(config=config,
force_unrestraint=True)
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(config=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]) -> TiramisuAPI:
"""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.config
for spath in spaths:
config = config.getconfig(spath)
config_bag = ConfigBag(config=config,
force_unrestraint=self.config_bag.force_unrestraint,
force_permissive=self.config_bag.force_permissive)
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.config.cfgimpl_get_home_by_path(path,
self.config_bag)
return TiramisuOption(name,
path,
index,
subconfig,
self.config_bag)
@count
def getapi(config: Union[Config, GroupConfig, MetaConfig]):
"""instanciate TiramisuAPI
:param config: Config object
:type descr: an instance of ``config.Config``
"""
return TiramisuAPI(config)