diff --git a/tiramisu/autolib.py b/tiramisu/autolib.py index 500f99f..c920be9 100644 --- a/tiramisu/autolib.py +++ b/tiramisu/autolib.py @@ -21,7 +21,7 @@ from .error import PropertiesOptionError, ConfigError, SlaveError, display_list from .i18n import _ from .setting import undefined -from .option.baseoption import DynSymLinkOption +from .option.symlinkoption import DynSymLinkOption from .storage import get_default_values_storages, get_default_settings_storages # ____________________________________________________________ diff --git a/tiramisu/option/__init__.py b/tiramisu/option/__init__.py index d770343..af12525 100644 --- a/tiramisu/option/__init__.py +++ b/tiramisu/option/__init__.py @@ -2,7 +2,8 @@ from .optiondescription import OptionDescription from .dynoptiondescription import DynOptionDescription from .syndynoptiondescription import SynDynOptionDescription from .masterslave import MasterSlaves -from .baseoption import SymLinkOption, DynSymLinkOption, submulti +from .baseoption import submulti +from .symlinkoption import SymLinkOption, DynSymLinkOption from .option import Option from .choiceoption import ChoiceOption from .booloption import BoolOption diff --git a/tiramisu/option/baseoption.py b/tiramisu/option/baseoption.py index 7a3f043..eeb9033 100644 --- a/tiramisu/option/baseoption.py +++ b/tiramisu/option/baseoption.py @@ -20,23 +20,18 @@ # ____________________________________________________________ import re from types import FunctionType -import sys import weakref +from inspect import signature from ..i18n import _ from ..setting import undefined from ..error import ConfigError -if sys.version_info[0] >= 3: # pragma: no cover - from inspect import signature -else: - from inspect import getargspec - STATIC_TUPLE = frozenset() submulti = 2 -NAME_REGEXP = re.compile(r'^[a-z][a-zA-Z\d_]*$') +NAME_REGEXP = re.compile(r'^[a-z][a-zA-Z\d_-]*$') FORBIDDEN_NAMES = frozenset(['iter_all', 'iter_group', 'find', 'find_first', 'make_dict', 'unwrap_from_path', 'read_only', 'read_write', 'getowner', 'set_contexts']) @@ -53,7 +48,10 @@ def valid_name(name): not name.startswith('cfgimpl_') -def validate_callback(callback, callback_params, type_, callbackoption): +def validate_callback(callback, + callback_params, + type_, + callbackoption): """validate function and parameter set for callback, validation, ... """ def _validate_option(option): @@ -67,7 +65,8 @@ def validate_callback(callback, callback_params, type_, callbackoption): else: raise ValueError(_('{}_params must have an option' ' not a {} for first argument' - ).format(type_, type(option))) + ).format(type_, + type(option))) if cur_opt != callbackoption: cur_opt._add_dependency(callbackoption) callbackoption._has_dependency = True @@ -77,8 +76,8 @@ def validate_callback(callback, callback_params, type_, callbackoption): if not isinstance(force_permissive, bool): raise ValueError(_('{}_params must have a boolean' ' not a {} for second argument' - ).format(type_, type( - force_permissive))) + ).format(type_, + type(force_permissive))) def _validate_callback(callbk): if isinstance(callbk, tuple): @@ -135,12 +134,19 @@ class Base(object): '__weakref__' ) - def __init__(self, name, doc, requires=None, properties=None, is_multi=False): + def __init__(self, + name, + doc, + requires=None, + properties=None, + is_multi=False): if not valid_name(name): raise ValueError(_('invalid name: "{0}" for option').format(name)) if requires is not None: - calc_properties, requires = validate_requires_arg(self, is_multi, - requires, name) + calc_properties, requires = validate_requires_arg(self, + is_multi, + requires, + name) else: calc_properties = frozenset() requires = undefined @@ -150,9 +156,8 @@ class Base(object): properties = tuple(list(properties) + ['empty']) if not isinstance(properties, tuple): raise TypeError(_('invalid properties type {0} for {1},' - ' must be a tuple').format( - type(properties), - name)) + ' must be a tuple').format(type(properties), + name)) if calc_properties != frozenset([]) and properties is not tuple(): set_forbidden_properties = calc_properties & set(properties) if set_forbidden_properties != frozenset(): @@ -161,8 +166,6 @@ class Base(object): list(set_forbidden_properties))) _setattr = object.__setattr__ _setattr(self, '_name', name) - if sys.version_info[0] < 3 and isinstance(doc, str): - doc = doc.decode('utf8') _setattr(self, '_informations', {'doc': doc}) if calc_properties is not undefined: _setattr(self, '_calc_properties', calc_properties) @@ -171,16 +174,12 @@ class Base(object): if properties: _setattr(self, '_properties', properties) - def _build_validator_params(self, validator, validator_params): - if sys.version_info[0] < 3: - func_args = getargspec(validator) - defaults = func_args.defaults - if defaults is None: - defaults = [] - args = func_args.args[0:len(func_args.args)-len(defaults)] - else: # pragma: no cover - func_params = signature(validator).parameters - args = [f.name for f in func_params.values() if f.default is f.empty] + def _build_validator_params(self, + validator, + validator_params): + + func_params = signature(validator).parameters + args = [f.name for f in func_params.values() if f.default is f.empty] if validator_params is not None: kwargs = list(validator_params.keys()) if '' in kwargs: @@ -206,7 +205,8 @@ class Base(object): validator_params[''] = tuple(params) return validator_params - def impl_has_dependency(self, self_is_dep=True): + def impl_has_dependency(self, + self_is_dep=True): if self_is_dep is True: if self.impl_is_master_slaves(): return True @@ -214,7 +214,8 @@ class Base(object): else: return hasattr(self, '_dependencies') - def _get_dependencies(self, context): + def _get_dependencies(self, + context): if context: od = context.cfgimpl_get_description() ret = set(getattr(self, '_dependencies', STATIC_TUPLE)) @@ -223,12 +224,17 @@ class Base(object): else: return ret - def _add_dependency(self, option): + def _add_dependency(self, + option): options = self._get_dependencies(None) options.add(weakref.ref(option)) self._dependencies = tuple(options) - def impl_set_callback(self, callback, callback_params=None, _init=False): + def impl_set_callback(self, + callback, + callback_params=None, + _init=False): + if callback is None and callback_params is not None: raise ValueError(_("params defined for a callback function but " "no callback defined" @@ -237,9 +243,13 @@ class Base(object): if not _init and self.impl_get_callback()[0] is not None: raise ConfigError(_("a callback is already set for {0}, " "cannot set another one's").format(self.impl_getname())) - self._validate_callback(callback, callback_params) + self._validate_callback(callback, + callback_params) if callback is not None: - validate_callback(callback, callback_params, 'callback', self) + validate_callback(callback, + callback_params, + 'callback', + self) val = getattr(self, '_val_call', (None,))[0] if callback_params is None or callback_params == {}: val_call = (callback,) @@ -281,7 +291,8 @@ class Base(object): if extra is not None: _setattr(self, '_extra', tuple([tuple(extra.keys()), tuple(extra.values())])) - def _impl_setsubdyn(self, subdyn): + def _impl_setsubdyn(self, + subdyn): self._subdyn = weakref.ref(subdyn) def impl_getrequires(self): @@ -299,16 +310,15 @@ class Base(object): # ____________________________________________________________ # information - def impl_get_information(self, key, default=undefined): + def impl_get_information(self, + key, + default=undefined): """retrieves one information's item :param key: the item string (ex: "help") """ def _is_string(infos): - if sys.version_info[0] >= 3: # pragma: no cover - return isinstance(infos, str) - else: - return isinstance(infos, str) or isinstance(infos, unicode) + return isinstance(infos, str) dico = self._informations if isinstance(dico, tuple): @@ -325,7 +335,9 @@ class Base(object): raise ValueError(_("information's item not found: {0}").format( key)) - def impl_set_information(self, key, value): + def impl_set_information(self, + key, + value): """updates the information's attribute (which is a dictionary) @@ -334,11 +346,10 @@ class Base(object): """ if self.impl_is_readonly(): raise AttributeError(_("'{0}' ({1}) object attribute '{2}' is" - " read-only").format( - self.__class__.__name__, - self, - #self.impl_getname(), - key)) + " read-only").format(self.__class__.__name__, + self, + #self.impl_getname(), + key)) self._informations[key] = value @@ -352,7 +363,9 @@ class BaseOption(Base): def __getstate__(self): raise NotImplementedError() - def __setattr__(self, name, value): + def __setattr__(self, + name, + value): """set once and only once some attributes in the option, like `_name`. `_name` cannot be changed one the option and pushed in the :class:`tiramisu.option.OptionDescription`. @@ -373,14 +386,14 @@ class BaseOption(Base): is_readonly = self.impl_is_readonly() if is_readonly: raise AttributeError(_("'{0}' ({1}) object attribute '{2}' is" - " read-only").format( - self.__class__.__name__, - self, - #self.impl_getname(), - name)) + " read-only").format(self.__class__.__name__, + self, + #self.impl_getname(), + name)) super(BaseOption, self).__setattr__(name, value) - def impl_getpath(self, context): + def impl_getpath(self, + context): return context.cfgimpl_get_description().impl_get_path_by_opt(self) def impl_has_callback(self): @@ -390,23 +403,19 @@ class BaseOption(Base): def _is_subdyn(self): return getattr(self, '_subdyn', None) is not None - def _impl_valid_unicode(self, value): - if sys.version_info[0] >= 3: # pragma: no cover - if not isinstance(value, str): - return ValueError(_('invalid string')) - else: - if not isinstance(value, unicode) and not isinstance(value, str): - return ValueError(_('invalid unicode or string')) + def _impl_valid_string(self, + value): + if not isinstance(value, str): + return ValueError(_('invalid string')) - def impl_get_display_name(self, dyn_name=None): + def impl_get_display_name(self, + dyn_name=None): name = self.impl_getdoc() if name is None or name == '': if dyn_name is not None: name = dyn_name else: name = self.impl_getname() - if sys.version_info[0] < 3 and isinstance(name, unicode): - name = name.encode('utf8') return name def reset_cache(self, @@ -432,7 +441,10 @@ class OnlyOption(BaseOption): __slots__ = tuple() -def validate_requires_arg(new_option, multi, requires, name): +def validate_requires_arg(new_option, + multi, + requires, + name): """check malformed requirements and tranform dict to internal tuple @@ -454,7 +466,13 @@ def validate_requires_arg(new_option, multi, requires, name): option._add_dependency(new_option) return option - def _set_expected(action, inverse, transitive, same_action, option, expected, operator): + def _set_expected(action, + inverse, + transitive, + same_action, + option, + expected, + operator): if inverse not in ret_requires[action]: ret_requires[action][inverse] = ([(option, [expected])], action, inverse, transitive, same_action, operator) else: @@ -465,7 +483,8 @@ def validate_requires_arg(new_option, multi, requires, name): else: ret_requires[action][inverse][0].append((option, [expected])) - def set_expected(require, ret_requires): + def set_expected(require, + ret_requires): expected = require['expected'] inverse = get_inverse(require) transitive = get_transitive(require) @@ -484,7 +503,13 @@ def validate_requires_arg(new_option, multi, requires, name): raise ValueError(_('malformed requirements expected value ' 'must be valid for option {0}' ': {1}').format(name, err)) - _set_expected(action, inverse, transitive, same_action, option, exp['value'], operator) + _set_expected(action, + inverse, + transitive, + same_action, + option, + exp['value'], + operator) else: option = get_option(require) if expected is not None: @@ -493,7 +518,13 @@ def validate_requires_arg(new_option, multi, requires, name): raise ValueError(_('malformed requirements expected value ' 'must be valid for option {0}' ': {1}').format(name, err)) - _set_expected(action, inverse, transitive, same_action, option, expected, operator) + _set_expected(action, + inverse, + transitive, + same_action, + option, + expected, + operator) def get_action(require): action = require['action'] @@ -572,123 +603,3 @@ def validate_requires_arg(new_option, multi, requires, name): require[2], require[3], require[4], require[5])) ret.append(tuple(ret_action)) return frozenset(config_action), tuple(ret) - - -class SymLinkOption(OnlyOption): - - def __init__(self, - name, - opt): - if not isinstance(opt, OnlyOption) or \ - opt.impl_is_symlinkoption(): - raise ValueError(_('malformed symlinkoption ' - 'must be an option ' - 'for symlink {0}').format(name)) - _setattr = object.__setattr__ - _setattr(self, '_name', name) - _setattr(self, '_opt', opt) - opt._add_dependency(self) - - def impl_has_dependency(self, self_is_dep=True): - """If self_is_dep is True, it has dependency (self._opt), so return True - if self_is_dep is False, cannot has validation or callback, so return False - """ - return self_is_dep is True - - def impl_is_symlinkoption(self): - return True - - def __getattr__(self, name, context=undefined): - return getattr(self.impl_getopt(), name) - - def impl_getopt(self): - return self._opt - - def impl_get_information(self, key, default=undefined): - return self.impl_getopt().impl_get_information(key, default) - - def impl_is_readonly(self): - return True - - def impl_getproperties(self): - return self.impl_getopt().impl_getproperties() - - def impl_get_callback(self): - return self.impl_getopt().impl_get_callback() - - def impl_has_callback(self): - "to know if a callback has been defined or not" - return self.impl_getopt().impl_has_callback() - - def impl_is_multi(self): - return self.impl_getopt().impl_is_multi() - - def _is_subdyn(self): - return getattr(self.impl_getopt(), '_subdyn', None) is not None - - def _get_consistencies(self): - return () - - def _has_consistencies(self): - return False - - -class DynSymLinkOption(object): - __slots__ = ('_rootpath', - '_opt', - '_suffix') - - def __init__(self, - opt, - rootpath, - suffix): - self._opt = opt - self._rootpath = rootpath - self._suffix = suffix - - def __getattr__(self, - name, - context=undefined): - return getattr(self.impl_getopt(), name) - - def impl_getname(self): - return self._opt.impl_getname() + self._suffix - - def impl_get_display_name(self): - return self.impl_getopt().impl_get_display_name(dyn_name=self.impl_getname()) - - def impl_getopt(self): - return self._opt - - def impl_getsuffix(self): - return self._suffix - - def impl_getpath(self, - context): - if self._rootpath == '': - return self.impl_getname() - return self._rootpath + '.' + self.impl_getname() - - def impl_validate(self, - value, - context=undefined, - validate=True, - force_index=None, - is_multi=None, - display_error=True, - display_warnings=True, - multi=None, - setting_properties=undefined): - return self.impl_getopt().impl_validate(value, - context, - validate, - force_index, - current_opt=self, - is_multi=is_multi, - display_error=display_error, - display_warnings=display_warnings, - multi=multi, - setting_properties=setting_properties) - - def impl_is_dynsymlinkoption(self): - return True diff --git a/tiramisu/option/broadcastoption.py b/tiramisu/option/broadcastoption.py index abafc45..f3fc8b8 100644 --- a/tiramisu/option/broadcastoption.py +++ b/tiramisu/option/broadcastoption.py @@ -31,7 +31,7 @@ class BroadcastOption(Option): _display_name = _('broadcast address') def _validate(self, value, context=undefined, current_opt=undefined): - err = self._impl_valid_unicode(value) + err = self._impl_valid_string(value) if err: return err if value.count('.') != 3: diff --git a/tiramisu/option/dateoption.py b/tiramisu/option/dateoption.py index b368827..3e2b0ea 100644 --- a/tiramisu/option/dateoption.py +++ b/tiramisu/option/dateoption.py @@ -30,7 +30,7 @@ class DateOption(Option): _display_name = _('date') def _validate(self, value, context=undefined, current_opt=undefined): - err = self._impl_valid_unicode(value) + err = self._impl_valid_string(value) if err: return err try: diff --git a/tiramisu/option/domainnameoption.py b/tiramisu/option/domainnameoption.py index dfe3552..3e12755 100644 --- a/tiramisu/option/domainnameoption.py +++ b/tiramisu/option/domainnameoption.py @@ -86,7 +86,7 @@ class DomainnameOption(Option): return 63 def _validate(self, value, context=undefined, current_opt=undefined): - err = self._impl_valid_unicode(value) + err = self._impl_valid_string(value) if err: return err diff --git a/tiramisu/option/ipoption.py b/tiramisu/option/ipoption.py index 306e6bb..d49297b 100644 --- a/tiramisu/option/ipoption.py +++ b/tiramisu/option/ipoption.py @@ -53,7 +53,7 @@ class IPOption(Option): def _validate(self, value, context=undefined, current_opt=undefined): # sometimes an ip term starts with a zero # but this does not fit in some case, for example bind does not like it - err = self._impl_valid_unicode(value) + err = self._impl_valid_string(value) if err: return err if value.count('.') != 3: diff --git a/tiramisu/option/netmaskoption.py b/tiramisu/option/netmaskoption.py index dcd9ef0..4dc154e 100644 --- a/tiramisu/option/netmaskoption.py +++ b/tiramisu/option/netmaskoption.py @@ -32,7 +32,7 @@ class NetmaskOption(Option): _display_name = _('netmask address') def _validate(self, value, context=undefined, current_opt=undefined): - err = self._impl_valid_unicode(value) + err = self._impl_valid_string(value) if err: return err if value.count('.') != 3: diff --git a/tiramisu/option/networkoption.py b/tiramisu/option/networkoption.py index 75f9e17..7733831 100644 --- a/tiramisu/option/networkoption.py +++ b/tiramisu/option/networkoption.py @@ -31,7 +31,7 @@ class NetworkOption(Option): _display_name = _('network address') def _validate(self, value, context=undefined, current_opt=undefined): - err = self._impl_valid_unicode(value) + err = self._impl_valid_string(value) if err: return err if value.count('.') != 3: diff --git a/tiramisu/option/option.py b/tiramisu/option/option.py index 0e2389b..6705dfc 100644 --- a/tiramisu/option/option.py +++ b/tiramisu/option/option.py @@ -23,7 +23,8 @@ import warnings import sys import weakref -from .baseoption import OnlyOption, submulti, DynSymLinkOption, validate_callback, STATIC_TUPLE +from .baseoption import OnlyOption, submulti, validate_callback, STATIC_TUPLE +from .symlinkoption import DynSymLinkOption from ..i18n import _ from ..setting import log, undefined, debug from ..autolib import carry_out_calculation @@ -746,7 +747,7 @@ class RegexpOption(Option): value, context=undefined, current_opt=undefined): - err = self._impl_valid_unicode(value) + err = self._impl_valid_string(value) if err: return err match = self._regexp.search(value) diff --git a/tiramisu/option/passwordoption.py b/tiramisu/option/passwordoption.py index 15b8a86..38d8f5b 100644 --- a/tiramisu/option/passwordoption.py +++ b/tiramisu/option/passwordoption.py @@ -30,6 +30,6 @@ class PasswordOption(Option): _display_name = _('password') def _validate(self, value, context=undefined, current_opt=undefined): - err = self._impl_valid_unicode(value) + err = self._impl_valid_string(value) if err: return err diff --git a/tiramisu/option/portoption.py b/tiramisu/option/portoption.py index c810d36..6f55252 100644 --- a/tiramisu/option/portoption.py +++ b/tiramisu/option/portoption.py @@ -87,7 +87,7 @@ class PortOption(Option): value = str(value) else: value = unicode(value) - err = self._impl_valid_unicode(value) + err = self._impl_valid_string(value) if err: return err if self._get_extra('_allow_range') and ":" in str(value): diff --git a/tiramisu/option/symlinkoption.py b/tiramisu/option/symlinkoption.py new file mode 100644 index 0000000..2ffc222 --- /dev/null +++ b/tiramisu/option/symlinkoption.py @@ -0,0 +1,147 @@ +# -*- 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 . +# +# The original `Config` design model is unproudly borrowed from +# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/ +# the whole pypy projet is under MIT licence +# ____________________________________________________________ +from .baseoption import OnlyOption +from ..i18n import _ +from ..setting import undefined + + +class SymLinkOption(OnlyOption): + + def __init__(self, + name, + opt): + if not isinstance(opt, OnlyOption) or \ + opt.impl_is_symlinkoption(): + raise ValueError(_('malformed symlinkoption ' + 'must be an option ' + 'for symlink {0}').format(name)) + _setattr = object.__setattr__ + _setattr(self, '_name', name) + _setattr(self, '_opt', opt) + opt._add_dependency(self) + + def impl_has_dependency(self, self_is_dep=True): + """If self_is_dep is True, it has dependency (self._opt), so return True + if self_is_dep is False, cannot has validation or callback, so return False + """ + return self_is_dep is True + + def impl_is_symlinkoption(self): + return True + + def __getattr__(self, + name, + context=undefined): + return getattr(self.impl_getopt(), name) + + def impl_getopt(self): + return self._opt + + def impl_get_information(self, + key, + default=undefined): + return self.impl_getopt().impl_get_information(key, default) + + def impl_is_readonly(self): + return True + + def impl_getproperties(self): + return self.impl_getopt().impl_getproperties() + + def impl_get_callback(self): + return self.impl_getopt().impl_get_callback() + + def impl_has_callback(self): + "to know if a callback has been defined or not" + return self.impl_getopt().impl_has_callback() + + def impl_is_multi(self): + return self.impl_getopt().impl_is_multi() + + def _is_subdyn(self): + return getattr(self.impl_getopt(), '_subdyn', None) is not None + + def _get_consistencies(self): + return () + + def _has_consistencies(self): + return False + + +class DynSymLinkOption(object): + __slots__ = ('_rootpath', + '_opt', + '_suffix') + + def __init__(self, + opt, + rootpath, + suffix): + self._opt = opt + self._rootpath = rootpath + self._suffix = suffix + + def __getattr__(self, + name, + context=undefined): + return getattr(self.impl_getopt(), name) + + def impl_getname(self): + return self._opt.impl_getname() + self._suffix + + def impl_get_display_name(self): + return self.impl_getopt().impl_get_display_name(dyn_name=self.impl_getname()) + + def impl_getopt(self): + return self._opt + + def impl_getsuffix(self): + return self._suffix + + def impl_getpath(self, + context): + if self._rootpath == '': + return self.impl_getname() + return self._rootpath + '.' + self.impl_getname() + + def impl_validate(self, + value, + context=undefined, + validate=True, + force_index=None, + is_multi=None, + display_error=True, + display_warnings=True, + multi=None, + setting_properties=undefined): + return self.impl_getopt().impl_validate(value, + context, + validate, + force_index, + current_opt=self, + is_multi=is_multi, + display_error=display_error, + display_warnings=display_warnings, + multi=multi, + setting_properties=setting_properties) + + def impl_is_dynsymlinkoption(self): + return True diff --git a/tiramisu/option/syndynoptiondescription.py b/tiramisu/option/syndynoptiondescription.py index 85d8a96..5298fb2 100644 --- a/tiramisu/option/syndynoptiondescription.py +++ b/tiramisu/option/syndynoptiondescription.py @@ -20,7 +20,7 @@ # ____________________________________________________________ from ..i18n import _ from ..setting import undefined -from .baseoption import DynSymLinkOption +from .symlinkoption import DynSymLinkOption class SynDynOptionDescription(object): diff --git a/tiramisu/option/urloption.py b/tiramisu/option/urloption.py index 65daf6f..c5fb989 100644 --- a/tiramisu/option/urloption.py +++ b/tiramisu/option/urloption.py @@ -33,7 +33,7 @@ class URLOption(DomainnameOption): _display_name = _('URL') def _validate(self, value, context=undefined, current_opt=undefined): - err = self._impl_valid_unicode(value) + err = self._impl_valid_string(value) if err: return err match = self.proto_re.search(value)