# -*- coding: utf-8 -*- # Copyright (C) 2017 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 . # ____________________________________________________________ from inspect import ismethod, getdoc from .error import APIError, PropertiesOptionError from .i18n import _ from .setting import owners, undefined from time import time from copy import deepcopy try: from .value import Multi except: Multi = list COUNT_TIME = False #COUNT_TIME = {} def count(func): global MOD_COUNT_TIME func_name = func.__name__ def wrapper(*args, **kwargs): time1 = time() ret = func(*args, **kwargs) time2 = time() diff = (time2 - time1) * 1000.0 MOD_COUNT_TIME[func_name]['max'] = max(MOD_COUNT_TIME[func_name]['max'], diff) MOD_COUNT_TIME[func_name]['min'] = min(MOD_COUNT_TIME[func_name]['min'], diff) MOD_COUNT_TIME[func_name]['total'] += diff MOD_COUNT_TIME[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: COUNT_TIME[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: global MOD_COUNT_TIME #print(MOD_COUNT_TIME) for func in MOD_COUNT_TIME: print('>', func) print('=> nb:', MOD_COUNT_TIME[func]['nb']) if MOD_COUNT_TIME[func]['nb'] != 0: print('=> min:', MOD_COUNT_TIME[func]['min']) print('=> max:', MOD_COUNT_TIME[func]['max']) print('=> moy:', MOD_COUNT_TIME[func]['total'] / MOD_COUNT_TIME[func]['nb']) MOD_COUNT_TIME = deepcopy(COUNT_TIME) class CommonTiramisuOption(object): icon = '\u2937' tmpl_help = u' {} {}: {}' allow_unrestraint = False slave_need_index = True def __init__(self, opt, path, index, config, setting_properties, force_permissive, force_unrestraint): self.opt = opt self.path = path self.index = index if self.slave_need_index: self._test_slave_index() self.config = config self.setting_properties = setting_properties self.force_permissive = force_permissive self.force_unrestraint = force_unrestraint if not self.allow_unrestraint: self._unrestraint_not_allowed(force_unrestraint) def _test_slave_index(self): if self.index is None and self.opt.impl_is_master_slaves('slave'): raise APIError('index must be set with a slave option') def _unrestraint_not_allowed(self, force_unrestraint): if force_unrestraint: name = self.__class__.__name__[14:].lower() raise APIError(_('{} cannot be unrestraint').format(name)) def __getattr__(self, name): if name == 'help': return self._help() else: if not hasattr(CommonTiramisuOption, name): raise APIError(_('unknown method {}').format(name)) else: super(CommonTiramisuOption, self).__getattribute__(name) def _help(self): txt = [] for func_name in dir(self): if not func_name.startswith('_'): func = getattr(self, func_name) if ismethod(func): txt.append(self.tmpl_help.format(self.icon, func_name, getdoc(func))) return '\n'.join(txt) class TiramisuOptionOption(CommonTiramisuOption): """get information from an option""" allow_unrestraint = True slave_need_index = False def __init__(self, opt, path, index, config, setting_properties, force_permissive, force_unrestraint): super(TiramisuOptionOption, self).__init__(opt, path, index, config, setting_properties, force_permissive, force_unrestraint) if config: self.values = self.config.cfgimpl_get_values() def ismulti(self): """test if option could have multi value""" return self.opt.impl_is_multi() def issubmulti(self): """test if option could have submulti value""" return self.opt.impl_is_submulti() def ismasterslaves(self): """test if option is a master or a slave""" return self.opt.impl_is_master_slaves() def ismaster(self): """test if option is a master""" return self.opt.impl_is_master_slaves('master') def isslave(self): """test if option is a slave""" return self.opt.impl_is_master_slaves('slave') def getname(self): return self.opt.impl_getname() def getdoc(self): return self.opt.impl_get_display_name() def getdefault(self): return self.opt.impl_getdefault() def getdefaultmulti(self): return self.opt.impl_getdefault_multi() class TiramisuOptionOwner(CommonTiramisuOption): """manager option's owner""" def __init__(self, opt, path, index, config, setting_properties, force_permissive, force_unrestraint): super(TiramisuOptionOwner, self).__init__(opt, path, index, config, setting_properties, force_permissive, force_unrestraint) if config: self.values = self.config.cfgimpl_get_values() def get(self): """get owner for a specified option""" return self.values.getowner(self.opt, self.path, self.setting_properties, index=self.index, force_permissive=self.force_permissive) @count def isdefault(self): """is option has defaut value""" return self.values.is_default_owner(self.opt, self.path, self.setting_properties, index=self.index, force_permissive=self.force_permissive) def set(self, owner): """get owner for a specified option""" try: obj_owner = getattr(owners, owner) except AttributeError: owners.addowner(owner) obj_owner = getattr(owners, owner) self.values.setowner(self.opt, self.path, obj_owner, self.index) class TiramisuOptionProperty(CommonTiramisuOption): """manager option's property""" #allow_unrestraint = True slave_need_index = False def __init__(self, opt, path, index, config, setting_properties, force_permissive, force_unrestraint): super(TiramisuOptionProperty, self).__init__(opt, path, index, config, setting_properties, force_permissive, force_unrestraint) if config: self.settings = config.cfgimpl_get_settings() def get(self): self._test_slave_index() return self.settings.getproperties(self.opt, self.path, self.setting_properties, index=self.index) def set(self, properties): """set properties for a specified option""" self.settings.setproperties(self.opt, self.path, properties) def reset(self): """reset all personalised properties """ self.settings.reset(opt=self.opt, path=self.path) class TiramisuOptionPermissive(CommonTiramisuOption): """manager option's property""" allow_unrestraint = True slave_need_index = False def __init__(self, opt, path, index, config, setting_properties, force_permissive, force_unrestraint): super(TiramisuOptionPermissive, self).__init__(opt, path, index, config, setting_properties, force_permissive, force_unrestraint) if config: self.settings = config.cfgimpl_get_settings() def get(self): """get permissive value for a specified path""" return self.settings.getpermissive(self.opt, self.path) def set(self, permissive): self.settings.setpermissive(self.opt, self.path, permissive) def reset(self, path): """reset all personalised permissive """ self.set(tuple()) class TiramisuOptionValue(CommonTiramisuOption): """manager option's value""" slave_need_index = False def __init__(self, opt, path, index, config, setting_properties, force_permissive, force_unrestraint): super(TiramisuOptionValue, self).__init__(opt, path, index, config, setting_properties, force_permissive, force_unrestraint) @count def get(self): self._test_slave_index() settings = self.config.cfgimpl_get_settings() value = self.config.getattr(self.path, index=self.index, setting_properties=self.setting_properties, force_permissive=self.force_permissive) if isinstance(value, Multi): value = list(value) return value @count def set(self, value): """set a value for a specified option""" self._test_slave_index() values = self.config.cfgimpl_get_values() if isinstance(value, list): while undefined in value: idx = value.index(undefined) value[idx] = values.getdefaultvalue(self.opt, self.path, self.setting_properties, idx) else: if value == undefined: value = values.getdefaultvalue(self.opt, self.path, self.setting_properties, self.index) self.config.setattr(self.path, value, index=self.index, setting_properties=self.setting_properties, force_permissive=self.force_permissive) @count def pop(self, index): """pop value for a specified master values """ self._test_slave_index() #FIXME only for master self.config.delattr(self.path, index=index, setting_properties=self.setting_properties, force_permissive=self.force_permissive) def reset(self): """reset value for a value""" self._test_slave_index() self.config.delattr(self.path, index=self.index, setting_properties=self.setting_properties, force_permissive=self.force_permissive) def len(self): #FIXME only for slave subconfig_path = self.path.rsplit('.', 1)[0] subconfig = self.config.getattr(subconfig_path, setting_properties=self.setting_properties, force_permissive=self.force_permissive) return subconfig.cfgimpl_get_length() class TiramisuOption(object): icon = '\u2937' tmpl_help = ' {} {}: {}' def __init__(self, opt, path, index, config, setting_properties, force_permissive, force_unrestraint): self.opt = opt self.path = path self.index = index self.config = config self.setting_properties = setting_properties self.force_permissive = force_permissive self.force_unrestraint = force_unrestraint self.registers = {} self.prefix = self.__class__.__name__ for module_name in globals().keys(): if module_name != self.prefix and module_name.startswith(self.prefix): module = globals()[module_name] func_name = module_name[len(self.prefix):].lower() self.registers[func_name] = module def _help(self): txt = [] for module_name, module in self.registers.items(): module_doc = getdoc(module) txt.append(self.tmpl_help.format(self.icon, module_name, module_doc)) txt.append(module(None, None).help) return '\n'.join(txt) def __getattr__(self, subfunc): if subfunc in self.registers: return self.registers[subfunc](self.opt, self.path, self.index, self.config, self.setting_properties, self.force_permissive, self.force_unrestraint) elif subfunc == 'help': return self._help() else: raise APIError(_('please specify a valid sub function')) class TiramisuContext(object): def __init__(self, config, force_permissive, force_unrestraint, setting_properties=None): if setting_properties is None: setting_properties = config.cfgimpl_get_settings().get_context_properties() self.config = config self.force_permissive = force_permissive self.force_unrestraint = force_unrestraint self.setting_properties = setting_properties class TiramisuContextOwner(TiramisuContext): def get(self): return self.config.cfgimpl_get_settings().getowner() class TiramisuContextOption(TiramisuContext): def find_first(self, name, type='option'): check_properties = self.force_unrestraint or self.force_unrestraint return self.config.find_first(byname=name, type_=type, setting_properties=self.setting_properties, force_permissive=self.force_permissive, check_properties=not self.force_unrestraint) def find(self, name, type='option'): return self.config.find(byname=name, type_=type, setting_properties=self.setting_properties, force_permissive=self.force_permissive, check_properties=not self.force_unrestraint) def get(self, path): return self.config.unwrap_from_path(path, validate=False, validate_properties=False) class TiramisuOptionDispatcher(TiramisuContextOption): def __init__(self, config, force_permissive, force_unrestraint): self.setting_properties = config.cfgimpl_get_settings().get_context_properties() super(TiramisuOptionDispatcher, self).__init__(config, force_permissive, force_unrestraint, self.setting_properties) def __call__(self, path, index=None): validate = not self.force_unrestraint if validate: s_properties = self.setting_properties else: s_properties = None opt = self.config.unwrap_from_path(path, setting_properties=s_properties, validate=validate, validate_properties=validate, force_permissive=self.force_permissive, index=index) if index is not None and not opt.impl_is_master_slaves('slave'): raise APIError('index must be set only with a slave option') if opt.impl_is_symlinkoption(): true_opt = opt.impl_getopt() true_path = true_opt.impl_getpath(self.config) self.config.unwrap_from_path(true_path, setting_properties=s_properties, validate=validate, validate_properties=validate, force_permissive=self.force_permissive, index=index) else: true_opt = None true_path = None return TiramisuOption(opt, path, index, self.config, self.setting_properties, self.force_permissive, self.force_unrestraint) class TiramisuContextConfig(TiramisuContext): def make_dict(self): return self.config.make_dict(self.setting_properties) class TiramisuConfigDispatcher(TiramisuContextConfig): def __init__(self, config, force_permissive, force_unrestraint): self.setting_properties = config.cfgimpl_get_settings().get_context_properties() super(TiramisuConfigDispatcher, self).__init__(config, force_permissive, force_unrestraint, self.setting_properties) def __call__(self, path): if path is None: subconfig = self.config else: subconfig = self.config.getconfig(path) return TiramisuAPI(subconfig, force_permissive=self.force_permissive, force_unrestraint=self.force_unrestraint) class TiramisuAPI(object): icon = '\u2937' tmpl_help = ' {} {}: {}' def __init__(self, config, force_permissive=False, force_unrestraint=False): self._config = config self.force_permissive = force_permissive self.force_unrestraint = force_unrestraint def __getattr__(self, subfunc): if subfunc == 'forcepermissive': return TiramisuAPI(self._config, force_permissive=True, force_unrestraint=self.force_unrestraint) elif subfunc == 'unrestraint': return TiramisuAPI(self._config, force_permissive=self.force_permissive, force_unrestraint=True) elif subfunc == 'help': return self._help() elif subfunc == 'owner': return TiramisuContextOwner(self._config, self.force_permissive, self.force_unrestraint) elif subfunc == 'config': return TiramisuConfigDispatcher(self._config, force_permissive=self.force_permissive, force_unrestraint=self.force_unrestraint) elif subfunc == 'option': return TiramisuOptionDispatcher(self._config, force_permissive=self.force_permissive, force_unrestraint=self.force_unrestraint) else: raise APIError(_('please specify a valid sub function ({})').format(subfunc)) def _help(self): txt = ['[forcepermissive]'] for module_name, module in self.registers.items(): module_doc = getdoc(module) txt.append(self.tmpl_help.format(self.icon, module_name, module_doc)) txt.append(module(None, None).help) return '\n'.join(txt) def read_only(self): self._config.read_write() def read_write(self): settings = self._config.cfgimpl_get_settings() self._config.read_write() # #FIXME ? settings.set_context_permissive(frozenset(['hidden'])) #/FIXME ? def getapi(config): """instanciate TiramisuAPI :param config: Config object :type descr: an instance of ``config.Config`` """ return TiramisuAPI(config)