reorganise

This commit is contained in:
Emmanuel Garette 2017-12-07 22:20:19 +01:00
parent a07e916153
commit fc787d4dbb
15 changed files with 263 additions and 203 deletions

View file

@ -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
# ____________________________________________________________

View file

@ -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

View file

@ -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

View file

@ -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:

View file

@ -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:

View file

@ -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

View file

@ -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:

View file

@ -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:

View file

@ -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:

View file

@ -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)

View file

@ -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

View file

@ -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):

View file

@ -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 <http://www.gnu.org/licenses/>.
#
# 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

View file

@ -20,7 +20,7 @@
# ____________________________________________________________
from ..i18n import _
from ..setting import undefined
from .baseoption import DynSymLinkOption
from .symlinkoption import DynSymLinkOption
class SynDynOptionDescription(object):

View file

@ -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)