add demoting_error_warning properties

This commit is contained in:
Emmanuel Garette 2018-12-24 09:30:58 +01:00
parent f9b9ccacf1
commit ca4d5e3e97
10 changed files with 87 additions and 32 deletions

View file

@ -350,7 +350,7 @@ def test_help():
cfg.help(_display=False)
cfg.config.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)

View file

@ -326,6 +326,25 @@ def test_requires_transitive():
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():
a = BoolOption('activate_service', '', True)
b = BoolOption('activate_service_web', '', True,

View file

@ -12,7 +12,7 @@
#
# 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 .function import Params, ParamOption, ParamValue, ParamContext
from .function import Params, ParamOption, ParamValue, ParamContext, tiramisu_copy
from .option import *
from .error import APIError
from .api import Config, MetaConfig, GroupConfig, MixConfig
@ -29,7 +29,8 @@ allfuncs = ['Params',
'GroupConfig',
'Config',
'APIError',
'undefined']
'undefined',
'tiramisu_copy']
allfuncs.extend(all_options)
del(all_options)
__all__ = tuple(allfuncs)

View file

@ -77,6 +77,7 @@ class TiramisuHelp:
class CommonTiramisu(TiramisuHelp):
_allow_optiondescription = True
_validate_properties = True
def _get_option(self) -> Any:
option = self._option_bag.option
@ -84,11 +85,14 @@ class CommonTiramisu(TiramisuHelp):
option = self._subconfig.cfgimpl_get_description().get_child(self._name,
self._option_bag.config_bag,
self._subconfig.cfgimpl_get_path())
self._option_bag.set_option(option,
self._option_bag.path,
self._option_bag.index,
self._option_bag.config_bag)
self._option_bag.config_bag.context.cfgimpl_get_settings().validate_properties(self._option_bag)
option_bag = OptionBag()
option_bag.set_option(option,
self._option_bag.path,
self._option_bag.index,
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
if index is not None:
if option.impl_is_optiondescription() or not option.impl_is_master_slaves('slave'):
@ -107,6 +111,7 @@ class CommonTiramisu(TiramisuHelp):
class CommonTiramisuOption(CommonTiramisu):
_allow_optiondescription = False
_slave_need_index = True
_validate_properties = False
def __init__(self,
name: str,
@ -141,6 +146,13 @@ class _TiramisuOptionOptionDescription(CommonTiramisuOption):
"""Get Tiramisu 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):
"""Test if option is a master or a slave"""
option = self._option_bag.option
@ -210,6 +222,10 @@ class _TiramisuOptionOption(_TiramisuOptionOptionDescription):
option = self._option_bag.option
return option.impl_is_master_slaves('slave')
def issymlinkoption(self) -> bool:
option = self._option_bag.option
return option.impl_is_symlinkoption()
def default(self):
"""Get default value for an option (not for optiondescription)"""
option = self._option_bag.option
@ -254,6 +270,7 @@ class TiramisuOptionOption(CommonTiramisuOption):
class TiramisuOptionOwner(CommonTiramisuOption):
#FIXME optiondescription must not have Owner!
"""Manage option's owner"""
def __init__(self,
@ -420,7 +437,7 @@ class _TiramisuOptionValueOption:
option = self._option_bag.option
self._test_slave_index()
return self._subconfig.getattr(self._name,
self._option_bag)
self._option_bag)
def set(self, value):
"""Change option's value"""
@ -505,13 +522,14 @@ class _TiramisuOptionValueOptionDescription:
flatten=False,
withvalue=undefined,
withoption=None,
withwarning: bool=False,
fullpath=False):
"""Dict with path as key and value"""
self._get_option()
name = self._option_bag.option.impl_getname()
subconfig = self._subconfig.get_subconfig(self._option_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.remove_warnings()
return subconfig.make_dict(config_bag=config_bag,
@ -817,11 +835,12 @@ class TiramisuContextValue(TiramisuContext):
flatten=False,
withvalue=undefined,
withoption=None,
withwarning: bool=False,
fullpath=False):
"""Dict with path as key and value"""
config_bag = self._config_bag
if config_bag.properties and 'warnings' in config_bag.properties:
config_bag = self._config_bag.copy()
if not withwarning and config_bag.properties and 'warnings' in config_bag.properties:
config_bag = config_bag.copy()
config_bag.remove_warnings()
return config_bag.context.make_dict(config_bag,
flatten=flatten,
@ -1218,7 +1237,7 @@ class TiramisuAPI(TiramisuHelp):
return TiramisuAPI(config_bag)
elif subfunc == 'unrestraint':
config_bag = self._config_bag.copy()
config_bag.properties = frozenset(['cache'])
config_bag.unrestraint()
return TiramisuAPI(config_bag)
elif subfunc == 'config':
config_type = self._config_bag.context.impl_type
@ -1235,8 +1254,7 @@ class TiramisuAPI(TiramisuHelp):
config_bag = self._config_bag
del config_bag.permissives
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):
return list(self._registers.keys()) + ['unrestraint', 'forcepermissive', 'config']

View file

@ -80,7 +80,7 @@ def manager_callback(callbk: Union[ParamOption, ParamValue],
if fromconsistency:
option_bag.fromconsistency = fromconsistency.copy()
if opt == option:
option_bag.config_bag.properties = frozenset()
option_bag.config_bag.unrestraint()
option_bag.config_bag.remove_validation()
try:
# get value

View file

@ -192,7 +192,7 @@ class ValueWarning(UserWarning):
class ValueErrorWarning(ValueWarning):
def __init__(self,
value_error):
super(ValueWarning, self).__init__(value_error, value_error.opt())
super(ValueErrorWarning, self).__init__(value_error, value_error.opt)
class ValueOptionError(ValueError):

View file

@ -75,3 +75,7 @@ class ParamContext(Param):
class ParamIndex(Param):
__slots__ = tuple()
def tiramisu_copy(val):
return val

View file

@ -179,6 +179,9 @@ class Option(BaseOption):
def impl_is_dynsymlinkoption(self) -> bool:
return False
def get_display_type(self) -> str:
return self._display_name
def impl_getdefault(self) -> Any:
"accessing the default value"
is_multi = self.impl_is_multi()
@ -347,7 +350,7 @@ class Option(BaseOption):
is_warnings_only)
except ValueError as err:
if config_bag is undefined or \
'demoting_error' not in config_bag.properties:
'demoting_error_warning' not in config_bag.properties:
raise ValueOptionError(val,
self._display_name,
option_bag.ori_option,
@ -638,7 +641,7 @@ class Option(BaseOption):
self._display_name,
current_opt.impl_get_display_name(),
err)
warnings.warn_explicit(ValueWarning(msg, weakref.ref(self)),
warnings.warn_explicit(ValueWarning(msg, weakref.ref(current_opt)),
ValueWarning,
self.__class__.__name__, 0)
else:

View file

@ -39,10 +39,8 @@ class StrOption(Option):
raise ValueError()
#UnicodeOption is same as StrOption in python 3+
class UnicodeOption(StrOption):
__slots__ = tuple()
_display_name = _('unicode')
#UnicodeOption is same as StrOption
UnicodeOption = StrOption
class RegexpOption(StrOption):
@ -52,8 +50,7 @@ class RegexpOption(StrOption):
value: Any,
option_bag: OptionBag,
current_opt: Option=Undefined) -> None:
if not isinstance(value, str):
raise ValueError(_('invalid string'))
super()._validate(value, option_bag, current_opt)
match = self._regexp.search(value)
if not match:
raise ValueError()

View file

@ -176,6 +176,7 @@ class OptionBag:
class ConfigBag:
__slots__ = ('context', # link to the current context
'properties', # properties for current context
'true_properties', # properties for current context
'permissives', # permissives for current context
)
def __init__(self, context, **kwargs):
@ -190,6 +191,8 @@ class ConfigBag:
if key == 'permissives':
self.permissives = self.context.cfgimpl_get_settings().get_context_permissives()
return self.permissives
if key == 'true_properties':
return self.properties
raise KeyError('unknown key {} for ConfigBag'.format(key)) # pragma: no cover
def remove_warnings(self):
@ -198,6 +201,10 @@ class ConfigBag:
def remove_validation(self):
self.properties = frozenset(self.properties - {'validator'})
def unrestraint(self):
self.true_properties = self.properties
self.properties = frozenset(['cache'])
def set_permissive(self):
self.properties = frozenset(self.properties | {'permissive'})
@ -210,14 +217,15 @@ class ConfigBag:
return
raise KeyError('unknown key {} for ConfigBag'.format(key)) # pragma: no cover
#def __setattr__(self, key, value):
# super().__setattr__(key, value)
# def __setattr__(self, key, value):
# super().__setattr__(key, value)
def copy(self):
kwargs = {}
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 for GroupConfig
continue
kwargs[key] = getattr(self, key)
return ConfigBag(**kwargs)
@ -503,23 +511,26 @@ class Settings(object):
elif option.impl_is_multi() and option_bag.index is not None:
is_indexed = True
config_bag = option_bag.config_bag.copy()
config_bag.set_permissive()
soption_bag = OptionBag()
soption_bag.set_option(option,
reqpath,
idx,
config_bag)
if option_bag.option == option:
soption_bag.config_bag.properties = frozenset()
soption_bag.config_bag.unrestraint()
soption_bag.config_bag.remove_validation()
soption_bag.apply_requires = False
else:
soption_bag.config_bag.properties = soption_bag.config_bag.true_properties
soption_bag.config_bag.set_permissive()
try:
value = context.getattr(reqpath,
soption_bag)
if is_indexed:
value = value[option_bag.index]
except PropertiesOptionError as err:
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 all_properties is None:
all_properties = []
@ -550,6 +561,8 @@ class Settings(object):
breaked = True
break
else:
if is_indexed:
value = value[option_bag.index]
if (not inverse and value in expected or
inverse and value not in expected):
if operator != 'and':