add demoting_error_warning properties
This commit is contained in:
parent
f9b9ccacf1
commit
ca4d5e3e97
10 changed files with 87 additions and 32 deletions
|
@ -350,7 +350,7 @@ def test_help():
|
||||||
cfg.help(_display=False)
|
cfg.help(_display=False)
|
||||||
cfg.config.help(_display=False)
|
cfg.config.help(_display=False)
|
||||||
cfg.option.help(_display=False)
|
cfg.option.help(_display=False)
|
||||||
cfg.option('o').help(_display=False)
|
#FIXMEcfg.option('o').help(_display=False)
|
||||||
cfg.option('o.s').help(_display=False)
|
cfg.option('o.s').help(_display=False)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -326,6 +326,25 @@ def test_requires_transitive():
|
||||||
assert frozenset(props) == frozenset(['disabled'])
|
assert frozenset(props) == frozenset(['disabled'])
|
||||||
|
|
||||||
|
|
||||||
|
def test_requires_transitive_unrestraint():
|
||||||
|
a = BoolOption('activate_service', '', True)
|
||||||
|
b = BoolOption('activate_service_web', '', True,
|
||||||
|
requires=[{'option': a, 'expected': False, 'action': 'disabled'}])
|
||||||
|
|
||||||
|
d = IPOption('ip_address_service_web', '',
|
||||||
|
requires=[{'option': b, 'expected': False, 'action': 'disabled'}])
|
||||||
|
od = OptionDescription('service', '', [a, b, d])
|
||||||
|
api = Config(od)
|
||||||
|
api.property.read_write()
|
||||||
|
api.option('activate_service').value.get()
|
||||||
|
api.option('activate_service_web').value.get()
|
||||||
|
api.option('ip_address_service_web').value.get()
|
||||||
|
api.option('activate_service').value.set(False)
|
||||||
|
#
|
||||||
|
assert api.unrestraint.option('activate_service_web').property.get() == {'disabled'}
|
||||||
|
assert api.unrestraint.option('ip_address_service_web').property.get() == {'disabled'}
|
||||||
|
|
||||||
|
|
||||||
def test_requires_transitive_owner():
|
def test_requires_transitive_owner():
|
||||||
a = BoolOption('activate_service', '', True)
|
a = BoolOption('activate_service', '', True)
|
||||||
b = BoolOption('activate_service_web', '', True,
|
b = BoolOption('activate_service_web', '', True,
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
#
|
#
|
||||||
# You should have received a copy of the GNU Lesser General Public License
|
# 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/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
from .function import Params, ParamOption, ParamValue, ParamContext
|
from .function import Params, ParamOption, ParamValue, ParamContext, tiramisu_copy
|
||||||
from .option import *
|
from .option import *
|
||||||
from .error import APIError
|
from .error import APIError
|
||||||
from .api import Config, MetaConfig, GroupConfig, MixConfig
|
from .api import Config, MetaConfig, GroupConfig, MixConfig
|
||||||
|
@ -29,7 +29,8 @@ allfuncs = ['Params',
|
||||||
'GroupConfig',
|
'GroupConfig',
|
||||||
'Config',
|
'Config',
|
||||||
'APIError',
|
'APIError',
|
||||||
'undefined']
|
'undefined',
|
||||||
|
'tiramisu_copy']
|
||||||
allfuncs.extend(all_options)
|
allfuncs.extend(all_options)
|
||||||
del(all_options)
|
del(all_options)
|
||||||
__all__ = tuple(allfuncs)
|
__all__ = tuple(allfuncs)
|
||||||
|
|
|
@ -77,6 +77,7 @@ class TiramisuHelp:
|
||||||
|
|
||||||
class CommonTiramisu(TiramisuHelp):
|
class CommonTiramisu(TiramisuHelp):
|
||||||
_allow_optiondescription = True
|
_allow_optiondescription = True
|
||||||
|
_validate_properties = True
|
||||||
|
|
||||||
def _get_option(self) -> Any:
|
def _get_option(self) -> Any:
|
||||||
option = self._option_bag.option
|
option = self._option_bag.option
|
||||||
|
@ -84,11 +85,14 @@ class CommonTiramisu(TiramisuHelp):
|
||||||
option = self._subconfig.cfgimpl_get_description().get_child(self._name,
|
option = self._subconfig.cfgimpl_get_description().get_child(self._name,
|
||||||
self._option_bag.config_bag,
|
self._option_bag.config_bag,
|
||||||
self._subconfig.cfgimpl_get_path())
|
self._subconfig.cfgimpl_get_path())
|
||||||
self._option_bag.set_option(option,
|
option_bag = OptionBag()
|
||||||
self._option_bag.path,
|
option_bag.set_option(option,
|
||||||
self._option_bag.index,
|
self._option_bag.path,
|
||||||
self._option_bag.config_bag)
|
self._option_bag.index,
|
||||||
self._option_bag.config_bag.context.cfgimpl_get_settings().validate_properties(self._option_bag)
|
self._option_bag.config_bag)
|
||||||
|
if self._validate_properties:
|
||||||
|
option_bag.config_bag.context.cfgimpl_get_settings().validate_properties(option_bag)
|
||||||
|
self._option_bag = option_bag
|
||||||
index = self._option_bag.index
|
index = self._option_bag.index
|
||||||
if index is not None:
|
if index is not None:
|
||||||
if option.impl_is_optiondescription() or not option.impl_is_master_slaves('slave'):
|
if option.impl_is_optiondescription() or not option.impl_is_master_slaves('slave'):
|
||||||
|
@ -107,6 +111,7 @@ class CommonTiramisu(TiramisuHelp):
|
||||||
class CommonTiramisuOption(CommonTiramisu):
|
class CommonTiramisuOption(CommonTiramisu):
|
||||||
_allow_optiondescription = False
|
_allow_optiondescription = False
|
||||||
_slave_need_index = True
|
_slave_need_index = True
|
||||||
|
_validate_properties = False
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
name: str,
|
name: str,
|
||||||
|
@ -141,6 +146,13 @@ class _TiramisuOptionOptionDescription(CommonTiramisuOption):
|
||||||
"""Get Tiramisu option"""
|
"""Get Tiramisu option"""
|
||||||
return self._option_bag.option
|
return self._option_bag.option
|
||||||
|
|
||||||
|
def type(self):
|
||||||
|
type_ = self._option_bag.option.__class__.__name__
|
||||||
|
if type_.endswith('Option'):
|
||||||
|
type_ = type_[:-6]
|
||||||
|
type_ = type_.lower()
|
||||||
|
return type_
|
||||||
|
|
||||||
def ismasterslaves(self):
|
def ismasterslaves(self):
|
||||||
"""Test if option is a master or a slave"""
|
"""Test if option is a master or a slave"""
|
||||||
option = self._option_bag.option
|
option = self._option_bag.option
|
||||||
|
@ -210,6 +222,10 @@ class _TiramisuOptionOption(_TiramisuOptionOptionDescription):
|
||||||
option = self._option_bag.option
|
option = self._option_bag.option
|
||||||
return option.impl_is_master_slaves('slave')
|
return option.impl_is_master_slaves('slave')
|
||||||
|
|
||||||
|
def issymlinkoption(self) -> bool:
|
||||||
|
option = self._option_bag.option
|
||||||
|
return option.impl_is_symlinkoption()
|
||||||
|
|
||||||
def default(self):
|
def default(self):
|
||||||
"""Get default value for an option (not for optiondescription)"""
|
"""Get default value for an option (not for optiondescription)"""
|
||||||
option = self._option_bag.option
|
option = self._option_bag.option
|
||||||
|
@ -254,6 +270,7 @@ class TiramisuOptionOption(CommonTiramisuOption):
|
||||||
|
|
||||||
|
|
||||||
class TiramisuOptionOwner(CommonTiramisuOption):
|
class TiramisuOptionOwner(CommonTiramisuOption):
|
||||||
|
#FIXME optiondescription must not have Owner!
|
||||||
"""Manage option's owner"""
|
"""Manage option's owner"""
|
||||||
|
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
|
@ -420,7 +437,7 @@ class _TiramisuOptionValueOption:
|
||||||
option = self._option_bag.option
|
option = self._option_bag.option
|
||||||
self._test_slave_index()
|
self._test_slave_index()
|
||||||
return self._subconfig.getattr(self._name,
|
return self._subconfig.getattr(self._name,
|
||||||
self._option_bag)
|
self._option_bag)
|
||||||
|
|
||||||
def set(self, value):
|
def set(self, value):
|
||||||
"""Change option's value"""
|
"""Change option's value"""
|
||||||
|
@ -505,13 +522,14 @@ class _TiramisuOptionValueOptionDescription:
|
||||||
flatten=False,
|
flatten=False,
|
||||||
withvalue=undefined,
|
withvalue=undefined,
|
||||||
withoption=None,
|
withoption=None,
|
||||||
|
withwarning: bool=False,
|
||||||
fullpath=False):
|
fullpath=False):
|
||||||
"""Dict with path as key and value"""
|
"""Dict with path as key and value"""
|
||||||
self._get_option()
|
self._get_option()
|
||||||
name = self._option_bag.option.impl_getname()
|
name = self._option_bag.option.impl_getname()
|
||||||
subconfig = self._subconfig.get_subconfig(self._option_bag)
|
subconfig = self._subconfig.get_subconfig(self._option_bag)
|
||||||
config_bag = self._option_bag.config_bag
|
config_bag = self._option_bag.config_bag
|
||||||
if config_bag.properties and 'warnings' in config_bag.properties:
|
if not withwarning and config_bag.properties and 'warnings' in config_bag.properties:
|
||||||
config_bag = config_bag.copy()
|
config_bag = config_bag.copy()
|
||||||
config_bag.remove_warnings()
|
config_bag.remove_warnings()
|
||||||
return subconfig.make_dict(config_bag=config_bag,
|
return subconfig.make_dict(config_bag=config_bag,
|
||||||
|
@ -817,11 +835,12 @@ class TiramisuContextValue(TiramisuContext):
|
||||||
flatten=False,
|
flatten=False,
|
||||||
withvalue=undefined,
|
withvalue=undefined,
|
||||||
withoption=None,
|
withoption=None,
|
||||||
|
withwarning: bool=False,
|
||||||
fullpath=False):
|
fullpath=False):
|
||||||
"""Dict with path as key and value"""
|
"""Dict with path as key and value"""
|
||||||
config_bag = self._config_bag
|
config_bag = self._config_bag
|
||||||
if config_bag.properties and 'warnings' in config_bag.properties:
|
if not withwarning and config_bag.properties and 'warnings' in config_bag.properties:
|
||||||
config_bag = self._config_bag.copy()
|
config_bag = config_bag.copy()
|
||||||
config_bag.remove_warnings()
|
config_bag.remove_warnings()
|
||||||
return config_bag.context.make_dict(config_bag,
|
return config_bag.context.make_dict(config_bag,
|
||||||
flatten=flatten,
|
flatten=flatten,
|
||||||
|
@ -1218,7 +1237,7 @@ class TiramisuAPI(TiramisuHelp):
|
||||||
return TiramisuAPI(config_bag)
|
return TiramisuAPI(config_bag)
|
||||||
elif subfunc == 'unrestraint':
|
elif subfunc == 'unrestraint':
|
||||||
config_bag = self._config_bag.copy()
|
config_bag = self._config_bag.copy()
|
||||||
config_bag.properties = frozenset(['cache'])
|
config_bag.unrestraint()
|
||||||
return TiramisuAPI(config_bag)
|
return TiramisuAPI(config_bag)
|
||||||
elif subfunc == 'config':
|
elif subfunc == 'config':
|
||||||
config_type = self._config_bag.context.impl_type
|
config_type = self._config_bag.context.impl_type
|
||||||
|
@ -1235,8 +1254,7 @@ class TiramisuAPI(TiramisuHelp):
|
||||||
config_bag = self._config_bag
|
config_bag = self._config_bag
|
||||||
del config_bag.permissives
|
del config_bag.permissives
|
||||||
return self._registers[subfunc](config_bag)
|
return self._registers[subfunc](config_bag)
|
||||||
else:
|
raise APIError(_('please specify a valid sub function ({})').format(subfunc))
|
||||||
raise APIError(_('please specify a valid sub function ({})').format(subfunc))
|
|
||||||
|
|
||||||
def __dir__(self):
|
def __dir__(self):
|
||||||
return list(self._registers.keys()) + ['unrestraint', 'forcepermissive', 'config']
|
return list(self._registers.keys()) + ['unrestraint', 'forcepermissive', 'config']
|
||||||
|
|
|
@ -80,7 +80,7 @@ def manager_callback(callbk: Union[ParamOption, ParamValue],
|
||||||
if fromconsistency:
|
if fromconsistency:
|
||||||
option_bag.fromconsistency = fromconsistency.copy()
|
option_bag.fromconsistency = fromconsistency.copy()
|
||||||
if opt == option:
|
if opt == option:
|
||||||
option_bag.config_bag.properties = frozenset()
|
option_bag.config_bag.unrestraint()
|
||||||
option_bag.config_bag.remove_validation()
|
option_bag.config_bag.remove_validation()
|
||||||
try:
|
try:
|
||||||
# get value
|
# get value
|
||||||
|
|
|
@ -192,7 +192,7 @@ class ValueWarning(UserWarning):
|
||||||
class ValueErrorWarning(ValueWarning):
|
class ValueErrorWarning(ValueWarning):
|
||||||
def __init__(self,
|
def __init__(self,
|
||||||
value_error):
|
value_error):
|
||||||
super(ValueWarning, self).__init__(value_error, value_error.opt())
|
super(ValueErrorWarning, self).__init__(value_error, value_error.opt)
|
||||||
|
|
||||||
|
|
||||||
class ValueOptionError(ValueError):
|
class ValueOptionError(ValueError):
|
||||||
|
|
|
@ -75,3 +75,7 @@ class ParamContext(Param):
|
||||||
|
|
||||||
class ParamIndex(Param):
|
class ParamIndex(Param):
|
||||||
__slots__ = tuple()
|
__slots__ = tuple()
|
||||||
|
|
||||||
|
|
||||||
|
def tiramisu_copy(val):
|
||||||
|
return val
|
||||||
|
|
|
@ -179,6 +179,9 @@ class Option(BaseOption):
|
||||||
def impl_is_dynsymlinkoption(self) -> bool:
|
def impl_is_dynsymlinkoption(self) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def get_display_type(self) -> str:
|
||||||
|
return self._display_name
|
||||||
|
|
||||||
def impl_getdefault(self) -> Any:
|
def impl_getdefault(self) -> Any:
|
||||||
"accessing the default value"
|
"accessing the default value"
|
||||||
is_multi = self.impl_is_multi()
|
is_multi = self.impl_is_multi()
|
||||||
|
@ -347,7 +350,7 @@ class Option(BaseOption):
|
||||||
is_warnings_only)
|
is_warnings_only)
|
||||||
except ValueError as err:
|
except ValueError as err:
|
||||||
if config_bag is undefined or \
|
if config_bag is undefined or \
|
||||||
'demoting_error' not in config_bag.properties:
|
'demoting_error_warning' not in config_bag.properties:
|
||||||
raise ValueOptionError(val,
|
raise ValueOptionError(val,
|
||||||
self._display_name,
|
self._display_name,
|
||||||
option_bag.ori_option,
|
option_bag.ori_option,
|
||||||
|
@ -638,7 +641,7 @@ class Option(BaseOption):
|
||||||
self._display_name,
|
self._display_name,
|
||||||
current_opt.impl_get_display_name(),
|
current_opt.impl_get_display_name(),
|
||||||
err)
|
err)
|
||||||
warnings.warn_explicit(ValueWarning(msg, weakref.ref(self)),
|
warnings.warn_explicit(ValueWarning(msg, weakref.ref(current_opt)),
|
||||||
ValueWarning,
|
ValueWarning,
|
||||||
self.__class__.__name__, 0)
|
self.__class__.__name__, 0)
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -39,10 +39,8 @@ class StrOption(Option):
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
|
|
||||||
|
|
||||||
#UnicodeOption is same as StrOption in python 3+
|
#UnicodeOption is same as StrOption
|
||||||
class UnicodeOption(StrOption):
|
UnicodeOption = StrOption
|
||||||
__slots__ = tuple()
|
|
||||||
_display_name = _('unicode')
|
|
||||||
|
|
||||||
|
|
||||||
class RegexpOption(StrOption):
|
class RegexpOption(StrOption):
|
||||||
|
@ -52,8 +50,7 @@ class RegexpOption(StrOption):
|
||||||
value: Any,
|
value: Any,
|
||||||
option_bag: OptionBag,
|
option_bag: OptionBag,
|
||||||
current_opt: Option=Undefined) -> None:
|
current_opt: Option=Undefined) -> None:
|
||||||
if not isinstance(value, str):
|
super()._validate(value, option_bag, current_opt)
|
||||||
raise ValueError(_('invalid string'))
|
|
||||||
match = self._regexp.search(value)
|
match = self._regexp.search(value)
|
||||||
if not match:
|
if not match:
|
||||||
raise ValueError()
|
raise ValueError()
|
||||||
|
|
|
@ -176,6 +176,7 @@ class OptionBag:
|
||||||
class ConfigBag:
|
class ConfigBag:
|
||||||
__slots__ = ('context', # link to the current context
|
__slots__ = ('context', # link to the current context
|
||||||
'properties', # properties for current context
|
'properties', # properties for current context
|
||||||
|
'true_properties', # properties for current context
|
||||||
'permissives', # permissives for current context
|
'permissives', # permissives for current context
|
||||||
)
|
)
|
||||||
def __init__(self, context, **kwargs):
|
def __init__(self, context, **kwargs):
|
||||||
|
@ -190,6 +191,8 @@ class ConfigBag:
|
||||||
if key == 'permissives':
|
if key == 'permissives':
|
||||||
self.permissives = self.context.cfgimpl_get_settings().get_context_permissives()
|
self.permissives = self.context.cfgimpl_get_settings().get_context_permissives()
|
||||||
return self.permissives
|
return self.permissives
|
||||||
|
if key == 'true_properties':
|
||||||
|
return self.properties
|
||||||
raise KeyError('unknown key {} for ConfigBag'.format(key)) # pragma: no cover
|
raise KeyError('unknown key {} for ConfigBag'.format(key)) # pragma: no cover
|
||||||
|
|
||||||
def remove_warnings(self):
|
def remove_warnings(self):
|
||||||
|
@ -198,6 +201,10 @@ class ConfigBag:
|
||||||
def remove_validation(self):
|
def remove_validation(self):
|
||||||
self.properties = frozenset(self.properties - {'validator'})
|
self.properties = frozenset(self.properties - {'validator'})
|
||||||
|
|
||||||
|
def unrestraint(self):
|
||||||
|
self.true_properties = self.properties
|
||||||
|
self.properties = frozenset(['cache'])
|
||||||
|
|
||||||
def set_permissive(self):
|
def set_permissive(self):
|
||||||
self.properties = frozenset(self.properties | {'permissive'})
|
self.properties = frozenset(self.properties | {'permissive'})
|
||||||
|
|
||||||
|
@ -210,14 +217,15 @@ class ConfigBag:
|
||||||
return
|
return
|
||||||
raise KeyError('unknown key {} for ConfigBag'.format(key)) # pragma: no cover
|
raise KeyError('unknown key {} for ConfigBag'.format(key)) # pragma: no cover
|
||||||
|
|
||||||
#def __setattr__(self, key, value):
|
# def __setattr__(self, key, value):
|
||||||
# super().__setattr__(key, value)
|
# super().__setattr__(key, value)
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
kwargs = {}
|
kwargs = {}
|
||||||
for key in self.__slots__:
|
for key in self.__slots__:
|
||||||
if key in ['properties', 'permissives'] and \
|
if key in ['properties', 'permissives', 'true_properties'] and \
|
||||||
not hasattr(self.context, '_impl_settings'):
|
not hasattr(self.context, '_impl_settings'):
|
||||||
|
# not for GroupConfig
|
||||||
continue
|
continue
|
||||||
kwargs[key] = getattr(self, key)
|
kwargs[key] = getattr(self, key)
|
||||||
return ConfigBag(**kwargs)
|
return ConfigBag(**kwargs)
|
||||||
|
@ -503,23 +511,26 @@ class Settings(object):
|
||||||
elif option.impl_is_multi() and option_bag.index is not None:
|
elif option.impl_is_multi() and option_bag.index is not None:
|
||||||
is_indexed = True
|
is_indexed = True
|
||||||
config_bag = option_bag.config_bag.copy()
|
config_bag = option_bag.config_bag.copy()
|
||||||
config_bag.set_permissive()
|
|
||||||
soption_bag = OptionBag()
|
soption_bag = OptionBag()
|
||||||
soption_bag.set_option(option,
|
soption_bag.set_option(option,
|
||||||
reqpath,
|
reqpath,
|
||||||
idx,
|
idx,
|
||||||
config_bag)
|
config_bag)
|
||||||
if option_bag.option == option:
|
if option_bag.option == option:
|
||||||
soption_bag.config_bag.properties = frozenset()
|
soption_bag.config_bag.unrestraint()
|
||||||
soption_bag.config_bag.remove_validation()
|
soption_bag.config_bag.remove_validation()
|
||||||
soption_bag.apply_requires = False
|
soption_bag.apply_requires = False
|
||||||
|
else:
|
||||||
|
soption_bag.config_bag.properties = soption_bag.config_bag.true_properties
|
||||||
|
soption_bag.config_bag.set_permissive()
|
||||||
try:
|
try:
|
||||||
value = context.getattr(reqpath,
|
value = context.getattr(reqpath,
|
||||||
soption_bag)
|
soption_bag)
|
||||||
if is_indexed:
|
|
||||||
value = value[option_bag.index]
|
|
||||||
except PropertiesOptionError as err:
|
except PropertiesOptionError as err:
|
||||||
properties = err.proptype
|
properties = err.proptype
|
||||||
|
# if not transitive, properties must be verify in current requires
|
||||||
|
# otherwise if same_action, property must be in properties
|
||||||
|
# otherwise add property in returned properties (if operator is 'and')
|
||||||
if not transitive:
|
if not transitive:
|
||||||
if all_properties is None:
|
if all_properties is None:
|
||||||
all_properties = []
|
all_properties = []
|
||||||
|
@ -550,6 +561,8 @@ class Settings(object):
|
||||||
breaked = True
|
breaked = True
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
|
if is_indexed:
|
||||||
|
value = value[option_bag.index]
|
||||||
if (not inverse and value in expected or
|
if (not inverse and value in expected or
|
||||||
inverse and value not in expected):
|
inverse and value not in expected):
|
||||||
if operator != 'and':
|
if operator != 'and':
|
||||||
|
|
Loading…
Reference in a new issue