844 lines
32 KiB
Python
844 lines
32 KiB
Python
# -*- coding: utf-8 -*-
|
|
"sets the options of the configuration objects Config object itself"
|
|
# Copyright (C) 2012-2023 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/>.
|
|
# ____________________________________________________________
|
|
from typing import Union, Set
|
|
from itertools import chain
|
|
from .error import PropertiesOptionError, ConstError, ConfigError, LeadershipError
|
|
from .i18n import _
|
|
|
|
|
|
# If cache and expire is enable, time before cache is expired.
|
|
# This delay start first time value/setting is set in cache, even if
|
|
# user access several time to value/setting
|
|
EXPIRATION_TIME = 5
|
|
|
|
#List of default properties (you can add new one if needed).
|
|
#
|
|
#For common properties and personalise properties, if a propery is set for
|
|
#an Option and for the Config together, Setting raise a PropertiesOptionError
|
|
#
|
|
#* Common properties:
|
|
#
|
|
#hidden
|
|
# option with this property can only get value in read only mode. This
|
|
# option is not available in read write mode.
|
|
#
|
|
#disabled
|
|
# option with this property cannot be set/get
|
|
#
|
|
#frozen
|
|
# cannot set value for option with this properties if 'frozen' is set in
|
|
# config
|
|
#
|
|
#* Special property:
|
|
#
|
|
#permissive
|
|
# option with 'permissive' cannot raise PropertiesOptionError for properties
|
|
# set in permissive
|
|
# config with 'permissive', whole option in this config cannot raise
|
|
# PropertiesOptionError for properties set in permissive
|
|
#
|
|
#mandatory
|
|
# should set value for option with this properties if 'mandatory' is set in
|
|
# config
|
|
# example: 'a', ['a'], [None] are valid
|
|
# None, [] are not valid
|
|
#
|
|
#empty
|
|
# raise mandatory PropertiesOptionError if multi or leader have empty value
|
|
# example: ['a'] is valid
|
|
# [None] is not valid
|
|
#
|
|
#unique
|
|
# raise ValueError if a value is set twice or more in a multi Option
|
|
#
|
|
#* Special Config properties:
|
|
#
|
|
#cache
|
|
# if set, enable cache settings and values
|
|
#
|
|
#expire
|
|
# if set, settings and values in cache expire after ``expiration_time``
|
|
#
|
|
#everything_frozen
|
|
# whole option in config are frozen (even if option have not frozen
|
|
# property)
|
|
#
|
|
#validator
|
|
# launch validator set by user in option (this property has no effect
|
|
# for internal validator)
|
|
#
|
|
#warnings
|
|
# display warnings during validation
|
|
#
|
|
#demoting_error_warning
|
|
# all value errors are convert to warning (ValueErrorWarning)
|
|
DEFAULT_PROPERTIES = frozenset(['cache', 'validator', 'warnings'])
|
|
SPECIAL_PROPERTIES = {'frozen', 'mandatory', 'empty', 'force_store_value'}
|
|
|
|
#Config can be in two defaut mode:
|
|
#
|
|
#read_only
|
|
# you can get all variables not disabled but you cannot set any variables
|
|
# if a value has a callback without any value, callback is launch and value
|
|
# of this variable can change
|
|
# you cannot access to mandatory variable without values
|
|
#
|
|
#read_write
|
|
# you can get all variables not disabled and not hidden
|
|
# you can set all variables not frozen
|
|
RO_APPEND = frozenset(['frozen',
|
|
'disabled',
|
|
'validator',
|
|
'everything_frozen',
|
|
'mandatory',
|
|
'empty',
|
|
'force_store_value',
|
|
])
|
|
RO_REMOVE = frozenset(['permissive',
|
|
'hidden',
|
|
])
|
|
RW_APPEND = frozenset(['frozen',
|
|
'disabled',
|
|
'validator',
|
|
'hidden',
|
|
'force_store_value',
|
|
])
|
|
RW_REMOVE = frozenset(['permissive',
|
|
'everything_frozen',
|
|
'mandatory',
|
|
'empty',
|
|
])
|
|
|
|
|
|
FORBIDDEN_SET_PROPERTIES = frozenset(['force_store_value'])
|
|
FORBIDDEN_SET_PERMISSIVES = frozenset(['force_default_on_freeze',
|
|
'force_metaconfig_on_freeze',
|
|
'force_store_value',
|
|
])
|
|
ALLOWED_LEADER_PROPERTIES = frozenset(['empty',
|
|
'notempty',
|
|
'notunique',
|
|
'unique',
|
|
'force_store_value',
|
|
'mandatory',
|
|
'force_default_on_freeze',
|
|
'force_metaconfig_on_freeze',
|
|
'frozen',
|
|
])
|
|
|
|
static_set = frozenset()
|
|
|
|
|
|
# ____________________________________________________________
|
|
class Undefined:
|
|
"""Object undefined, means that there is not value
|
|
"""
|
|
# pylint: disable=too-few-public-methods
|
|
def __str__(self): # pragma: no cover
|
|
return 'Undefined'
|
|
|
|
__repr__ = __str__
|
|
|
|
|
|
undefined = Undefined()
|
|
|
|
|
|
class OptionBag:
|
|
"""Object to store information for an option
|
|
"""
|
|
__slots__ = ('option', # current option
|
|
'path',
|
|
'index',
|
|
'config_bag',
|
|
'ori_option', # original option (for example useful for symlinkoption)
|
|
'properties', # properties of current option
|
|
'apply_requires', # apply requires or not for this option
|
|
)
|
|
|
|
# pylint: disable=too-many-arguments
|
|
def __init__(self,
|
|
option,
|
|
index,
|
|
config_bag,
|
|
path=None,
|
|
properties=undefined,
|
|
ori_option=None,
|
|
apply_requires=True,
|
|
):
|
|
self.index = index
|
|
self.config_bag = config_bag
|
|
self.option = option
|
|
if ori_option is not None:
|
|
self.ori_option = ori_option
|
|
if config_bag is undefined:
|
|
self.path = path
|
|
elif path:
|
|
self.path = path
|
|
elif option:
|
|
self.path = option.impl_getpath()
|
|
context = config_bag.context
|
|
if '.' not in self.path and option == context.get_description():
|
|
self.properties = None
|
|
elif properties is undefined:
|
|
settings = context.get_settings()
|
|
try:
|
|
self.properties = settings.getproperties(self,
|
|
apply_requires=apply_requires,
|
|
)
|
|
except ConfigError:
|
|
self.properties = None
|
|
if properties is not undefined:
|
|
self.properties = properties
|
|
|
|
def __getattr__(self, key):
|
|
if key == 'ori_option':
|
|
return self.option
|
|
if key == 'apply_requires':
|
|
return True
|
|
return None
|
|
|
|
def copy(self):
|
|
"""copy OptionBag
|
|
"""
|
|
option_bag = OptionBag(None,
|
|
None,
|
|
None,
|
|
)
|
|
for key in self.__slots__:
|
|
setattr(option_bag, key, getattr(self, key))
|
|
return option_bag
|
|
|
|
|
|
class ConfigBag:
|
|
"""Object to store information for context
|
|
"""
|
|
__slots__ = ('context', # link to the current context
|
|
'properties', # properties for current context
|
|
'true_properties', # properties for current context
|
|
'is_unrestraint',
|
|
'permissives', # permissives for current context
|
|
'expiration_time', # EXPIRATION_TIME
|
|
)
|
|
|
|
def __init__(self,
|
|
context,
|
|
properties: set,
|
|
permissives: frozenset,
|
|
**kwargs):
|
|
self.context = context
|
|
self.properties = properties
|
|
self.permissives = permissives
|
|
for key, value in kwargs.items():
|
|
setattr(self, key, value)
|
|
|
|
def __getattr__(self, key):
|
|
if key == 'true_properties':
|
|
return self.properties
|
|
if key == 'expiration_time':
|
|
self.expiration_time = EXPIRATION_TIME # pylint: disable=attribute-defined-outside-init
|
|
return self.expiration_time
|
|
if key == 'is_unrestraint':
|
|
return False
|
|
raise KeyError(f'unknown key "{key}" for ConfigBag') # pragma: no cover
|
|
|
|
def nowarnings(self):
|
|
"""do not warnings
|
|
"""
|
|
self.properties = frozenset(self.properties - {'warnings'})
|
|
|
|
def remove_validation(self):
|
|
"""do not validate option
|
|
"""
|
|
self.properties = frozenset(self.properties - {'validator'})
|
|
|
|
def unrestraint(self):
|
|
"""do not restraint access to option
|
|
"""
|
|
self.is_unrestraint = True # pylint: disable=attribute-defined-outside-init
|
|
self.true_properties = self.properties # pylint: disable=attribute-defined-outside-init
|
|
self.properties = frozenset(['cache'])
|
|
|
|
def set_permissive(self):
|
|
"""set permissive
|
|
"""
|
|
self.properties = frozenset(self.properties | {'permissive'})
|
|
|
|
def copy(self):
|
|
"""copy the config
|
|
"""
|
|
kwargs = {}
|
|
for key in self.__slots__:
|
|
kwargs[key] = getattr(self, key)
|
|
return ConfigBag(**kwargs)
|
|
|
|
|
|
# ____________________________________________________________
|
|
class _NameSpace:
|
|
"""convenient class that emulates a module
|
|
and builds constants (that is, unique names)
|
|
when attribute is added, we cannot delete it
|
|
"""
|
|
|
|
def __setattr__(self,
|
|
name,
|
|
value,
|
|
):
|
|
if name in self.__dict__:
|
|
raise ConstError(_("can't rebind {0}").format(name))
|
|
self.__dict__[name] = value
|
|
|
|
def __delattr__(self,
|
|
name,
|
|
):
|
|
raise ConstError(_("can't unbind {0}").format(name))
|
|
|
|
|
|
class GroupModule(_NameSpace):
|
|
"emulates a module to manage unique group (OptionDescription) names"
|
|
# pylint: disable=too-few-public-methods
|
|
class GroupType(str):
|
|
"""allowed normal group (OptionDescription) names
|
|
*normal* means : groups that are not leader
|
|
"""
|
|
|
|
class DefaultGroupType(GroupType):
|
|
"""groups that are default (typically 'default')"""
|
|
|
|
class LeadershipGroupType(GroupType):
|
|
"""allowed normal group (OptionDescription) names
|
|
*leadership* means : groups that have the 'leadership' attribute set
|
|
"""
|
|
|
|
class RootGroupType(GroupType):
|
|
"""root means this is the root optiondescription of whole config
|
|
"""
|
|
|
|
def addgroup(self, name):
|
|
"""add a new group type
|
|
"""
|
|
setattr(groups, name, groups.GroupType(name))
|
|
|
|
|
|
class OwnerModule(_NameSpace):
|
|
"""emulates a module to manage unique owner names.
|
|
|
|
owners are living in `Config._value_owners`
|
|
"""
|
|
# pylint: disable=too-few-public-methods
|
|
class Owner(str):
|
|
"""allowed owner names
|
|
"""
|
|
|
|
class DefaultOwner(Owner):
|
|
"""groups that are default (typically 'default')"""
|
|
|
|
def addowner(self, name):
|
|
"""
|
|
:param name: the name of the new owner
|
|
"""
|
|
setattr(owners, name, owners.Owner(name))
|
|
|
|
|
|
# ____________________________________________________________
|
|
# populate groups
|
|
groups = GroupModule()
|
|
|
|
# groups.default: default group set when creating a new optiondescription
|
|
groups.default = groups.DefaultGroupType('default') # pylint: disable=attribute-defined-outside-init
|
|
|
|
# groups.leadership: leadership group is a special optiondescription, all suboptions should
|
|
# be multi option and all values should have same length, to find
|
|
# leader's option, the optiondescription's name should be same than de
|
|
# leader's option"""
|
|
groups.leadership = groups.LeadershipGroupType('leadership') # pylint: disable=attribute-defined-outside-init
|
|
|
|
# groups.root: this group is the root optiondescription of whole config
|
|
groups.root = groups.RootGroupType('root') # pylint: disable=attribute-defined-outside-init
|
|
|
|
|
|
# ____________________________________________________________
|
|
# populate owners with default attributes
|
|
owners = OwnerModule()
|
|
|
|
# default: is the config owner after init time
|
|
owners.default = owners.DefaultOwner('default') # pylint: disable=attribute-defined-outside-init
|
|
|
|
# user: is the generic is the generic owner
|
|
owners.addowner('user')
|
|
|
|
#forced: special owner when value is forced
|
|
owners.addowner('forced')
|
|
|
|
|
|
forbidden_owners = (owners.default, owners.forced) # pylint: disable=no-member
|
|
|
|
|
|
# ____________________________________________________________
|
|
class Settings:
|
|
"``config.Config()``'s configuration options settings"
|
|
__slots__ = ('_properties',
|
|
'_permissives',
|
|
'_permissives',
|
|
'__weakref__',
|
|
'ro_append',
|
|
'ro_remove',
|
|
'rw_append',
|
|
'rw_remove',
|
|
'default_properties',
|
|
)
|
|
|
|
def __init__(self):
|
|
"""
|
|
initializer
|
|
|
|
:param context: the root config
|
|
:param storage: the storage type
|
|
"""
|
|
# generic owner
|
|
self._properties = {}
|
|
self._permissives = {}
|
|
self.default_properties = DEFAULT_PROPERTIES
|
|
self.ro_append = RO_APPEND
|
|
self.ro_remove = RO_REMOVE
|
|
self.rw_append = RW_APPEND
|
|
self.rw_remove = RW_REMOVE
|
|
|
|
# ____________________________________________________________
|
|
# get properties and permissive methods
|
|
|
|
def get_context_properties(self,
|
|
cache,
|
|
):
|
|
"""get context properties
|
|
"""
|
|
is_cached, props, _ = cache.getcache(None,
|
|
'context_props',
|
|
expiration=False,
|
|
)
|
|
if not is_cached:
|
|
props = self.get_stored_properties(None,
|
|
None,
|
|
self.default_properties,
|
|
)
|
|
cache.setcache(None,
|
|
props,
|
|
type_='properties',
|
|
)
|
|
return props
|
|
|
|
def get_stored_properties(self,
|
|
path: Union[None, str],
|
|
index: Union[None, int],
|
|
default_properties: Set[str],
|
|
) -> Set[str]:
|
|
"""Get the properties modified by user for a path or index
|
|
"""
|
|
if path not in self._properties or index not in self._properties[path]:
|
|
return frozenset(default_properties)
|
|
return self._properties[path][index]
|
|
|
|
def getproperties(self,
|
|
option_bag,
|
|
apply_requires=True,
|
|
uncalculated=False,
|
|
help_property=False,
|
|
transitive_raise=True,
|
|
):
|
|
"""get properties
|
|
"""
|
|
# pylint: disable=too-many-branches
|
|
option = option_bag.option
|
|
if option.impl_is_symlinkoption():
|
|
option = option.impl_getopt()
|
|
if apply_requires and not uncalculated and not help_property:
|
|
cache = option_bag.config_bag.context.properties_cache
|
|
is_cached, props, validated = cache.getcache(option_bag, # pylint: disable=unused-variable
|
|
'self_props',
|
|
)
|
|
else:
|
|
is_cached = False
|
|
if not is_cached:
|
|
props = set()
|
|
# if index, get option's properties (without index) too
|
|
p_props = self.get_stored_properties(option_bag.path,
|
|
None,
|
|
option.impl_getproperties(),
|
|
)
|
|
if option_bag.index is not None:
|
|
p_props = chain(p_props,
|
|
self.get_stored_properties(option_bag.path,
|
|
option_bag.index,
|
|
option.impl_getproperties(),
|
|
)
|
|
)
|
|
for prop in p_props:
|
|
if uncalculated or isinstance(prop, str):
|
|
if not help_property:
|
|
props.add(prop)
|
|
else:
|
|
props.add((prop, prop))
|
|
elif apply_requires:
|
|
try:
|
|
if not help_property:
|
|
new_prop = prop.execute(option_bag,
|
|
for_settings=True,
|
|
)
|
|
else:
|
|
new_prop = prop.help(option_bag,
|
|
for_settings=True,
|
|
)
|
|
if isinstance(new_prop, str):
|
|
new_prop = (new_prop, new_prop)
|
|
if new_prop is None:
|
|
continue
|
|
except ConfigError as err:
|
|
if transitive_raise:
|
|
raise err from err
|
|
continue
|
|
if (not help_property and not isinstance(new_prop, str)) or \
|
|
(help_property and not isinstance(new_prop, tuple)):
|
|
raise ValueError(_('invalid property type {type(new_prop)} for '
|
|
'{option_bag.option.impl_getname()} with '
|
|
'{prop.function.__name__} function'))
|
|
if not option.impl_is_optiondescription() and \
|
|
option.impl_is_leader() and \
|
|
new_prop not in ALLOWED_LEADER_PROPERTIES:
|
|
raise LeadershipError(_('leader cannot have "{new_prop}" property'))
|
|
props.add(new_prop)
|
|
props -= self.getpermissives(option_bag)
|
|
if not uncalculated and apply_requires and \
|
|
not option_bag.config_bag.is_unrestraint and \
|
|
not help_property and transitive_raise:
|
|
cache.setcache(option_bag,
|
|
props,
|
|
type_='properties',
|
|
)
|
|
return props
|
|
|
|
def get_context_permissives(self):
|
|
"""get context permissives
|
|
"""
|
|
return self.getpermissives(None)
|
|
|
|
def _getpermissives(self,
|
|
path,
|
|
index,
|
|
):
|
|
if not path in self._permissives:
|
|
ret = frozenset()
|
|
else:
|
|
ret = self._permissives[path].get(index, frozenset())
|
|
return ret
|
|
|
|
def getpermissives(self,
|
|
option_bag,
|
|
):
|
|
"""get permissive
|
|
"""
|
|
if option_bag is None:
|
|
path = None
|
|
index = None
|
|
else:
|
|
opt = option_bag.option
|
|
if opt.impl_is_symlinkoption():
|
|
opt = opt.impl_getopt()
|
|
path = opt.impl_getpath()
|
|
else:
|
|
path = option_bag.path
|
|
index = option_bag.index
|
|
permissives = self._getpermissives(path,
|
|
None,
|
|
)
|
|
if index is not None:
|
|
option_permissives = self._permissives.get(path, {}).get(index, set())
|
|
permissives = frozenset(option_permissives | permissives)
|
|
return permissives
|
|
|
|
#____________________________________________________________
|
|
# set methods
|
|
def set_context_properties(self, properties, context):
|
|
"""set context properties
|
|
"""
|
|
self._properties.setdefault(None, {})[None] = properties
|
|
context.reset_cache(None)
|
|
|
|
def setproperties(self,
|
|
option_bag,
|
|
properties,
|
|
):
|
|
"""save properties for specified path
|
|
(never save properties if same has option properties)
|
|
"""
|
|
opt = option_bag.option
|
|
if not opt.impl_is_optiondescription() and opt.impl_is_leader():
|
|
not_allowed_properties = properties - ALLOWED_LEADER_PROPERTIES
|
|
if not_allowed_properties:
|
|
raise LeadershipError(_('leader cannot have "{list(not_allowed_properties)}" '
|
|
'property'))
|
|
if ('force_default_on_freeze' in properties or \
|
|
'force_metaconfig_on_freeze' in properties) and 'frozen' not in properties:
|
|
raise LeadershipError(_('a leader ({opt.impl_get_display_name()}) cannot have '
|
|
'"force_default_on_freeze" or '
|
|
'"force_metaconfig_on_freeze" property without "frozen"'))
|
|
self._properties.setdefault(option_bag.path, {})[option_bag.index] = properties
|
|
# values too because of follower values could have a PropertiesOptionError has value
|
|
option_bag.config_bag.context.reset_cache(option_bag)
|
|
option_bag.properties = properties
|
|
|
|
def set_context_permissives(self,
|
|
permissives,
|
|
):
|
|
"""set context permissive
|
|
"""
|
|
self.setpermissives(None,
|
|
permissives,
|
|
)
|
|
|
|
def setpermissives(self,
|
|
option_bag,
|
|
permissives,
|
|
):
|
|
"""
|
|
enables us to put the permissives in the storage
|
|
|
|
:param path: the option's path
|
|
:param type: str
|
|
:param opt: if an option object is set, the path is extracted.
|
|
it is better (faster) to set the path parameter
|
|
instead of passing a :class:`tiramisu.option.Option()` object.
|
|
"""
|
|
if not isinstance(permissives, frozenset):
|
|
raise TypeError(_('permissive must be a frozenset'))
|
|
if option_bag is not None:
|
|
path = option_bag.path
|
|
index = option_bag.index
|
|
else:
|
|
path = None
|
|
index = None
|
|
forbidden_permissives = FORBIDDEN_SET_PERMISSIVES & permissives
|
|
if forbidden_permissives:
|
|
raise ConfigError(_('cannot add those permissives: {0}').format(
|
|
' '.join(forbidden_permissives)))
|
|
self._permissives.setdefault(path, {})[index] = permissives
|
|
if option_bag is not None:
|
|
option_bag.config_bag.context.reset_cache(option_bag)
|
|
|
|
#____________________________________________________________
|
|
# reset methods
|
|
def _get_path_index_config_option(self,
|
|
bag: Union[OptionBag, ConfigBag],
|
|
msg: str,
|
|
):
|
|
if isinstance(bag, ConfigBag):
|
|
path = None
|
|
index = None
|
|
config_bag = bag
|
|
option_bag = None
|
|
else:
|
|
assert not bag.option.impl_is_symlinkoption(), \
|
|
_(msg).format(bag.option.impl_get_display_name())
|
|
path = bag.path
|
|
index = bag.index
|
|
config_bag = bag.config_bag
|
|
option_bag = bag
|
|
return path, index, config_bag, option_bag
|
|
|
|
def reset(self,
|
|
bag: Union[OptionBag, ConfigBag],
|
|
):
|
|
"""reset property
|
|
"""
|
|
path, index, config_bag, option_bag = \
|
|
self._get_path_index_config_option(bag,
|
|
"can't reset properties to "
|
|
"the symlinkoption \"{}\"",
|
|
)
|
|
if path in self._properties and index in self._properties[path]:
|
|
del self._properties[path][index]
|
|
config_bag.context.reset_cache(option_bag)
|
|
|
|
def reset_permissives(self,
|
|
bag: Union[OptionBag, ConfigBag],
|
|
):
|
|
"""reset permission
|
|
"""
|
|
path, index, config_bag, option_bag = \
|
|
self._get_path_index_config_option(bag,
|
|
"can't reset permissives to "
|
|
"the symlinkoption \"{}\"",
|
|
)
|
|
if path in self._permissives and index in self._permissives[path]:
|
|
del self._permissives[path][index]
|
|
config_bag.context.reset_cache(option_bag)
|
|
|
|
#____________________________________________________________
|
|
# validate properties
|
|
def calc_raises_properties(self,
|
|
option_bag,
|
|
apply_requires=True,
|
|
uncalculated=False,
|
|
transitive_raise=True,
|
|
):
|
|
"""raise if needed
|
|
"""
|
|
if not uncalculated and apply_requires and option_bag.properties is not None:
|
|
option_properties = option_bag.properties
|
|
else:
|
|
option_properties = self.getproperties(option_bag,
|
|
apply_requires=apply_requires,
|
|
uncalculated=uncalculated,
|
|
transitive_raise=transitive_raise,
|
|
)
|
|
return self._calc_raises_properties(option_bag.config_bag.properties,
|
|
option_bag.config_bag.permissives,
|
|
option_properties,
|
|
)
|
|
|
|
def _calc_raises_properties(self,
|
|
context_properties,
|
|
context_permissives,
|
|
option_properties,
|
|
):
|
|
raises_properties = context_properties - SPECIAL_PROPERTIES
|
|
# remove global permissive properties
|
|
if raises_properties and 'permissive' in raises_properties:
|
|
raises_properties -= context_permissives
|
|
properties = option_properties & raises_properties
|
|
# at this point it should not remain any property for the option
|
|
return properties
|
|
|
|
def validate_properties(self,
|
|
option_bag,
|
|
need_help=True,
|
|
):
|
|
"""check properties
|
|
"""
|
|
config_properties = option_bag.config_bag.properties
|
|
if not config_properties or config_properties == frozenset(['cache']):
|
|
# if no global property
|
|
return
|
|
for transitive_raise in [False, True]:
|
|
properties = self.calc_raises_properties(option_bag,
|
|
transitive_raise=transitive_raise,
|
|
)
|
|
if properties != frozenset():
|
|
if need_help:
|
|
help_properties = dict(self.getproperties(option_bag,
|
|
help_property=True,
|
|
transitive_raise=transitive_raise,
|
|
))
|
|
calc_properties = []
|
|
for property_ in self._calc_raises_properties(option_bag.config_bag.properties,
|
|
option_bag.config_bag.permissives,
|
|
set(help_properties.keys()),
|
|
):
|
|
calc_properties.append(help_properties[property_])
|
|
calc_properties = frozenset(calc_properties)
|
|
else:
|
|
calc_properties = properties
|
|
raise PropertiesOptionError(option_bag,
|
|
properties,
|
|
self,
|
|
help_properties=calc_properties,
|
|
)
|
|
|
|
def validate_mandatory(self,
|
|
value,
|
|
option_bag,
|
|
):
|
|
"""verify if option is mandatory without value
|
|
"""
|
|
if 'mandatory' not in option_bag.config_bag.properties:
|
|
return
|
|
values = option_bag.config_bag.context.get_values()
|
|
if not ('permissive' in option_bag.config_bag.properties and
|
|
'mandatory' in option_bag.config_bag.permissives) and \
|
|
'mandatory' in option_bag.properties and values.isempty(option_bag,
|
|
value,
|
|
False,
|
|
):
|
|
raise PropertiesOptionError(option_bag,
|
|
['mandatory'],
|
|
self,
|
|
)
|
|
if 'empty' in option_bag.properties and values.isempty(option_bag,
|
|
value,
|
|
True,
|
|
):
|
|
raise PropertiesOptionError(option_bag,
|
|
['empty'],
|
|
self,
|
|
)
|
|
|
|
def validate_frozen(self,
|
|
option_bag,
|
|
):
|
|
"""verify if option is frozen
|
|
"""
|
|
if option_bag.config_bag.properties and \
|
|
('everything_frozen' in option_bag.config_bag.properties or
|
|
('frozen' in option_bag.config_bag.properties and \
|
|
'frozen' in option_bag.properties)) and \
|
|
not (('permissive' in option_bag.config_bag.properties) and
|
|
'frozen' in option_bag.config_bag.permissives):
|
|
raise PropertiesOptionError(option_bag,
|
|
['frozen'],
|
|
self,
|
|
)
|
|
return False
|
|
#____________________________________________________________
|
|
# read only/read write
|
|
|
|
def _read(self,
|
|
remove,
|
|
append,
|
|
config_bag,
|
|
):
|
|
props = self.get_stored_properties(None,
|
|
None,
|
|
self.default_properties,
|
|
)
|
|
modified = False
|
|
if remove & props:
|
|
props = props - remove
|
|
modified = True
|
|
if append & props != append:
|
|
props = props | append
|
|
modified = True
|
|
if modified:
|
|
self.set_context_properties(frozenset(props),
|
|
config_bag.context,
|
|
)
|
|
|
|
def read_only(self,
|
|
config_bag,
|
|
):
|
|
"convenience method to freeze, hide and disable"
|
|
self._read(self.ro_remove,
|
|
self.ro_append,
|
|
config_bag,
|
|
)
|
|
|
|
def read_write(self,
|
|
config_bag,
|
|
):
|
|
"convenience method to freeze, hide and disable"
|
|
self._read(self.rw_remove,
|
|
self.rw_append,
|
|
config_bag,
|
|
)
|