refactoring values
This commit is contained in:
parent
d058e2946b
commit
e6d5d349c8
|
@ -89,6 +89,14 @@ def test_groups_with_master():
|
|||
interface1.set_group_type(groups.master)
|
||||
assert interface1.get_group_type() == groups.master
|
||||
|
||||
def test_groups_with_master_in_config():
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
|
||||
interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
interface1.set_group_type(groups.master)
|
||||
cfg = Config(interface1)
|
||||
assert interface1.get_group_type() == groups.master
|
||||
|
||||
def test_allowed_groups():
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
|
||||
|
@ -108,7 +116,7 @@ def test_sub_group_in_master_group():
|
|||
invalid_group = OptionDescription('ip_admin_eth0', '', [subgroup, ip_admin_eth0, netmask_admin_eth0])
|
||||
raises(ConfigError, "invalid_group.set_group_type(groups.master)")
|
||||
|
||||
def test_group_has_always_multis():
|
||||
def test_group_always_has_multis():
|
||||
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
|
||||
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau")
|
||||
group = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"pretty small and local configuration management tool"
|
||||
# Copyright (C) 2012 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2012-2013 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 General Public License as published by
|
||||
|
@ -27,7 +27,7 @@ from tiramisu.error import (PropertiesOptionError, ConfigError, NotFoundError,
|
|||
from tiramisu.option import (OptionDescription, Option, SymLinkOption,
|
||||
apply_requires)
|
||||
from tiramisu.setting import groups, owners, Setting
|
||||
from tiramisu.value import OptionValues, Multi
|
||||
from tiramisu.value import OptionValues
|
||||
|
||||
# ____________________________________________________________
|
||||
class Config(object):
|
||||
|
@ -92,32 +92,23 @@ class Config(object):
|
|||
- settles various default values for options
|
||||
"""
|
||||
self._validate_duplicates(self._cfgimpl_descr._children)
|
||||
#max len for a master/slave group
|
||||
max_len_child = 0
|
||||
if self._cfgimpl_descr.group_type == groups.master:
|
||||
mastername = self._cfgimpl_descr._name
|
||||
masteropt = getattr(self._cfgimpl_descr, mastername)
|
||||
self._cfgimpl_values.master_groups[masteropt] = []
|
||||
|
||||
for child in self._cfgimpl_descr._children:
|
||||
if isinstance(child, OptionDescription):
|
||||
self._validate_duplicates(child._children)
|
||||
self._cfgimpl_subconfigs[child] = Config(child, parent=self,
|
||||
context=self._cfgimpl_context)
|
||||
if (self._cfgimpl_descr.group_type == groups.master and
|
||||
child != masteropt):
|
||||
self._cfgimpl_values.master_groups[child] = []
|
||||
self._cfgimpl_values.master_groups[masteropt].append(child)
|
||||
|
||||
# def cfgimpl_update(self):
|
||||
# """dynamically adds `Option()` or `OptionDescription()`
|
||||
# """
|
||||
# # FIXME this is an update for new options in the schema only
|
||||
# # see the update_child() method of the descr object
|
||||
# for child in self._cfgimpl_descr._children:
|
||||
# if isinstance(child, Option):
|
||||
# if child._name not in self._cfgimpl_values:
|
||||
# if child.is_multi():
|
||||
# self._cfgimpl_values[child._name] = Multi(
|
||||
# copy(child.getdefault()), config=self, opt=child)
|
||||
# else:
|
||||
# self._cfgimpl_values[child._name] = copy(child.getdefault())
|
||||
# child.setowner(self, owners.default)
|
||||
# elif isinstance(child, OptionDescription):
|
||||
# if child._name not in self._cfgimpl_values:
|
||||
# self._cfgimpl_values[child._name] = Config(child, parent=self)
|
||||
|
||||
if self._cfgimpl_descr.group_type == groups.master:
|
||||
print self._cfgimpl_values.master_groups
|
||||
# ____________________________________________________________
|
||||
# attribute methods
|
||||
def __setattr__(self, name, value):
|
||||
|
@ -130,8 +121,7 @@ class Config(object):
|
|||
return setattr(homeconfig, name, value)
|
||||
if type(getattr(self._cfgimpl_descr, name)) != SymLinkOption:
|
||||
self._validate(name, getattr(self._cfgimpl_descr, name))
|
||||
self.setoption(name, value,
|
||||
self._cfgimpl_context._cfgimpl_settings.getowner())
|
||||
self.setoption(name, value)
|
||||
|
||||
def _validate(self, name, opt_or_descr, permissive=False):
|
||||
"validation for the setattr and the getattr"
|
||||
|
@ -156,15 +146,15 @@ class Config(object):
|
|||
def __getattr__(self, name):
|
||||
return self._getattr(name)
|
||||
|
||||
def fill_multi(self, opt, result, use_default_multi=False, default_multi=None):
|
||||
"""fills a multi option with default and calculated values
|
||||
"""
|
||||
# FIXME C'EST ENCORE DU N'IMPORTE QUOI
|
||||
if not isinstance(result, list):
|
||||
_result = [result]
|
||||
else:
|
||||
_result = result
|
||||
return Multi(_result, self._cfgimpl_context, opt)
|
||||
# def fill_multi(self, opt, result, use_default_multi=False, default_multi=None):
|
||||
# """fills a multi option with default and calculated values
|
||||
# """
|
||||
# # FIXME C'EST ENCORE DU N'IMPORTE QUOI
|
||||
# if not isinstance(result, list):
|
||||
# _result = [result]
|
||||
# else:
|
||||
# _result = result
|
||||
# return Multi(_result, self._cfgimpl_context, opt)
|
||||
|
||||
def _getattr(self, name, permissive=False):
|
||||
"""
|
||||
|
@ -227,40 +217,16 @@ class Config(object):
|
|||
def setoption(self, name, value, who=None):
|
||||
"""effectively modifies the value of an Option()
|
||||
(typically called by the __setattr__)
|
||||
|
||||
:param who: an object that lives in `setting.owners`
|
||||
"""
|
||||
child = getattr(self._cfgimpl_descr, name)
|
||||
if type(child) != SymLinkOption:
|
||||
if who == None:
|
||||
who = self._cfgimpl_context._cfgimpl_settings.owner
|
||||
if child.is_multi():
|
||||
if not isinstance(who, owners.DefaultOwner):
|
||||
if type(value) != Multi:
|
||||
if type(value) == list:
|
||||
value = Multi(value, self._cfgimpl_context, child)
|
||||
else:
|
||||
raise ConfigError("invalid value for option:"
|
||||
" {0} that is set to multi".format(name))
|
||||
else:
|
||||
value = self.fill_multi(child, child.getdefault(),
|
||||
use_default_multi=True,
|
||||
default_multi=child.getdefault_multi())
|
||||
if not isinstance(who, owners.Owner):
|
||||
raise TypeError("invalid owner [{0}] for option: {1}".format(
|
||||
str(who), name))
|
||||
child.setoption(self, value)
|
||||
child.setowner(self, who)
|
||||
else:
|
||||
homeconfig = self._cfgimpl_get_toplevel()
|
||||
child.setoption(homeconfig, value)
|
||||
child.setoption(self, value)
|
||||
|
||||
def set(self, **kwargs):
|
||||
"""
|
||||
do what I mean"-interface to option setting. Searches all paths
|
||||
starting from that config for matches of the optional arguments
|
||||
and sets the found option if the match is not ambiguous.
|
||||
|
||||
|
||||
:param kwargs: dict of name strings to values.
|
||||
"""
|
||||
all_paths = [p.split(".") for p in self.getpaths(allpaths=True)]
|
||||
|
@ -276,8 +242,7 @@ class Config(object):
|
|||
pass
|
||||
except Exception, e:
|
||||
raise e # HiddenOptionError or DisabledOptionError
|
||||
homeconfig.setoption(name, value,
|
||||
self._cfgimpl_context._cfgimpl_settings.getowner())
|
||||
homeconfig.setoption(name, value)
|
||||
elif len(candidates) > 1:
|
||||
raise AmbigousOptionError(
|
||||
'more than one option that ends with %s' % (key, ))
|
||||
|
@ -380,7 +345,7 @@ class Config(object):
|
|||
"""iteration on groups objects only.
|
||||
All groups are returned if `group_type` is `None`, otherwise the groups
|
||||
can be filtered by categories (families, or whatever).
|
||||
|
||||
|
||||
:param group_type: if defined, is an instance of `groups.GroupType`
|
||||
or `groups.MasterGroupType` that lives in
|
||||
`setting.groups`
|
||||
|
|
|
@ -23,3 +23,5 @@ class MandatoryError(Exception):
|
|||
pass
|
||||
class NoValueReturned(Exception):
|
||||
pass
|
||||
class OptionValueError(Exception):
|
||||
pass
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"option types and option description for the configuration management"
|
||||
# Copyright (C) 2012 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2012-2013 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 General Public License as published by
|
||||
|
@ -27,7 +27,6 @@ from tiramisu.error import (ConfigError, ConflictConfigError, NotFoundError,
|
|||
PropertiesOptionError)
|
||||
from tiramisu.autolib import carry_out_calculation
|
||||
from tiramisu.setting import groups, owners
|
||||
from tiramisu.value import Multi
|
||||
|
||||
requires_actions = [('hide', 'show'), ('enable', 'disable'), ('freeze', 'unfreeze')]
|
||||
|
||||
|
@ -217,7 +216,7 @@ class Option(HiddenBaseType, DisabledBaseType):
|
|||
def reset(self, config):
|
||||
"""resets the default value and owner
|
||||
"""
|
||||
config.setoption(self._name, self.getdefault(), owners.default)
|
||||
config._cfgimpl_context._cfgimpl_values.reset(self)
|
||||
|
||||
def is_default_owner(self, config):
|
||||
"""
|
||||
|
@ -241,9 +240,9 @@ class Option(HiddenBaseType, DisabledBaseType):
|
|||
# so '' is considered as being None
|
||||
if not self.is_multi() and value == '':
|
||||
value = None
|
||||
if self.is_multi() and '' in value:
|
||||
value = Multi([{'': None}.get(i, i) for i in value],
|
||||
config._cfgimpl_context, self)
|
||||
# if self.is_multi() and '' in value:
|
||||
# value = Multi([{'': None}.get(i, i) for i in value],
|
||||
# config._cfgimpl_context, self)
|
||||
if config._cfgimpl_context._cfgimpl_settings.is_mandatory() \
|
||||
and ((self.is_multi() and value == []) or \
|
||||
(not self.is_multi() and value is None)):
|
||||
|
@ -261,10 +260,6 @@ class Option(HiddenBaseType, DisabledBaseType):
|
|||
raise TypeError('cannot change the value to %s for '
|
||||
'option %s this option is frozen' % (str(value), name))
|
||||
apply_requires(self, config)
|
||||
# if type(config._cfgimpl_context._cfgimpl_values[self]) == Multi:
|
||||
# config._cfgimpl_context._cfgimpl_values.previous_values[self] = list(config._cfgimpl_context._cfgimpl_values[self])
|
||||
# else:
|
||||
# config._cfgimpl_context._cfgimpl_values.previous_values[self] = config._cfgimpl_context._cfgimpl_values[self]
|
||||
config._cfgimpl_context._cfgimpl_values[self] = value
|
||||
|
||||
def getkey(self, value):
|
||||
|
@ -341,7 +336,7 @@ class SymLinkOption(object):
|
|||
self.opt = opt
|
||||
|
||||
def setoption(self, config, value):
|
||||
setattr(config, self.path, value)
|
||||
setattr(config._cfgimpl_get_toplevel(), self.path, value)
|
||||
|
||||
def __getattr__(self, name):
|
||||
if name in ('_name', 'path', 'opt', 'setoption'):
|
||||
|
|
|
@ -95,6 +95,26 @@ def populate_owners():
|
|||
|
||||
# names are in the module now
|
||||
populate_owners()
|
||||
|
||||
class MultiTypeModule(_const):
|
||||
class MultiType(str):
|
||||
pass
|
||||
class DefaultMultiType(MultiType):
|
||||
pass
|
||||
class MasterMultiType(MultiType):
|
||||
pass
|
||||
class SlaveMultiType(MultiType):
|
||||
pass
|
||||
|
||||
multitypes = MultiTypeModule()
|
||||
|
||||
def populate_multitypes():
|
||||
setattr(multitypes, 'default', multitypes.DefaultMultiType('default'))
|
||||
setattr(multitypes, 'master', multitypes.MasterMultiType('master'))
|
||||
setattr(multitypes, 'slave', multitypes.SlaveMultiType('slave'))
|
||||
|
||||
populate_multitypes()
|
||||
|
||||
#____________________________________________________________
|
||||
class Setting():
|
||||
"``Config()``'s configuration options"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"takes care of the option's values and multi values"
|
||||
# Copyright (C) 2012 Team tiramisu (see AUTHORS for all contributors)
|
||||
# Copyright (C) 2013 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 General Public License as published by
|
||||
|
@ -25,10 +25,16 @@ from tiramisu.setting import owners
|
|||
|
||||
class OptionValues(object):
|
||||
def __init__(self, context):
|
||||
"""
|
||||
Initializes the values's dict.
|
||||
|
||||
:param context: the context is the home config's values and properties
|
||||
"""
|
||||
self.owners = {}
|
||||
"Config's root indeed is in charge of the `Option()`'s values"
|
||||
self.values = {}
|
||||
self.previous_values = {}
|
||||
self.master_groups = {}
|
||||
self.context = context
|
||||
|
||||
def _get_value(self, opt):
|
||||
|
@ -42,24 +48,42 @@ class OptionValues(object):
|
|||
return opt.getdefault()
|
||||
return self.values[opt]
|
||||
|
||||
def _is_empty(self, opt):
|
||||
def reset(self, opt):
|
||||
if opt in self.values:
|
||||
self.set_previous_value(opt)
|
||||
del(self.values[opt])
|
||||
self.setowner(opt, owners.default)
|
||||
|
||||
def set_previous_value(self, opt):
|
||||
if opt in self.values:
|
||||
old_value = self.values[opt]
|
||||
else:
|
||||
old_value = None
|
||||
if type(old_value) == Multi:
|
||||
self.previous_values[opt] = list(old_value)
|
||||
else:
|
||||
self.previous_values[opt] = old_value
|
||||
|
||||
def _is_empty(self, opt, value=None):
|
||||
"convenience method to know if an option is empty"
|
||||
if value is not None:
|
||||
return False
|
||||
if (not opt.is_multi() and self._get_value(opt) == None) or \
|
||||
(opt.is_multi() and (self._get_value(opt) == [] or \
|
||||
None in self._get_value(opt))):
|
||||
return True
|
||||
return False
|
||||
|
||||
def _test_mandatory(self, opt):
|
||||
def _test_mandatory(self, opt, value=None):
|
||||
# mandatory options
|
||||
mandatory = self.context._cfgimpl_settings.mandatory
|
||||
if opt.is_mandatory() and mandatory:
|
||||
if self._is_empty(opt) and \
|
||||
if self._is_empty(opt, value) and \
|
||||
opt.is_empty_by_default():
|
||||
raise MandatoryError("option: {0} is mandatory "
|
||||
"and shall have a value".format(opt._name))
|
||||
|
||||
def fill_multi(self, opt, result, use_default_multi=False, default_multi=None):
|
||||
def fill_multi(self, opt, result):
|
||||
"""fills a multi option with default and calculated values
|
||||
"""
|
||||
value = self._get_value(opt)
|
||||
|
@ -71,6 +95,7 @@ class OptionValues(object):
|
|||
|
||||
def __getitem__(self, opt):
|
||||
# options with callbacks
|
||||
value = self._get_value(opt)
|
||||
if opt.has_callback():
|
||||
if (not opt.is_frozen() or \
|
||||
not opt.is_forced_on_freeze()) and \
|
||||
|
@ -83,68 +108,57 @@ class OptionValues(object):
|
|||
pass
|
||||
else:
|
||||
if opt.is_multi():
|
||||
#FIXME revoir les multis
|
||||
_result = fill_multi(opt, result)
|
||||
value = fill_multi(opt, result)
|
||||
else:
|
||||
# this result **shall not** be a list
|
||||
if isinstance(result, list):
|
||||
raise ConfigError('invalid calculated value returned'
|
||||
' for option {0} : shall not be a list'.format(name))
|
||||
_result = result
|
||||
if _result != None and not opt.validate(_result,
|
||||
raise ConfigError('invalid calculated value returned '
|
||||
'for option {0} : shall not be a list'.format(name))
|
||||
value = result
|
||||
if value != None and not opt.validate(value,
|
||||
self.context._cfgimpl_settings.validator):
|
||||
raise ConfigError('invalid calculated value returned'
|
||||
' for option {0}'.format(name))
|
||||
self.values[opt] = _result
|
||||
self.owners[opt] = owners.default
|
||||
# frozen and force default
|
||||
if not opt.has_callback() and opt.is_forced_on_freeze():
|
||||
value = opt.getdefault()
|
||||
if opt.is_multi():
|
||||
#FIXME le fill_multi
|
||||
value = self.fill_multi(opt, value,
|
||||
use_default_multi=True,
|
||||
default_multi=opt.getdefault_multi())
|
||||
self.values[opt] = value
|
||||
self.owners[opt] = owners.default
|
||||
self._test_mandatory(opt)
|
||||
value = self._get_value(opt)
|
||||
value = self.fill_multi(opt, value)
|
||||
self._test_mandatory(opt, value)
|
||||
return value
|
||||
|
||||
def __setitem__(self, opt, value):
|
||||
if opt in self.values:
|
||||
old_value = self.values[opt]
|
||||
else:
|
||||
old_value = None
|
||||
if type(old_value) == Multi:
|
||||
self.previous_values[opt] = list(value)
|
||||
else:
|
||||
self.previous_values[opt] = value
|
||||
self.set_previous_value(opt)
|
||||
self.values[opt] = value
|
||||
self.setowner(opt, self.context._cfgimpl_settings.getowner())
|
||||
|
||||
def __contains__(self, opt):
|
||||
return opt in self.values
|
||||
|
||||
#____________________________________________________________
|
||||
def setowner(self, opt, owner):
|
||||
pass
|
||||
if isinstance(owner, owners.Owner):
|
||||
self.owners[opt] = owner
|
||||
else:
|
||||
raise OptionValueError("Bad owner: " + str(owner))
|
||||
|
||||
def getowner(self, opt):
|
||||
return self.owners.get(opt, owners.default)
|
||||
|
||||
# ____________________________________________________________
|
||||
# multi types
|
||||
class Multi(list):
|
||||
"""multi options values container
|
||||
that support item notation for the values of multi options"""
|
||||
def __init__(self, lst, context, opt):
|
||||
def __init__(self, lst, context, opt, multitype=settings.multitypes.default):
|
||||
"""
|
||||
:param lst: the Multi wraps a list value
|
||||
:param context: the context has the settings and the values
|
||||
:param context: the home config that has the settings and the values
|
||||
:param opt: the option object that have this Multi value
|
||||
"""
|
||||
self.settings = context._cfgimpl_settings
|
||||
self.opt = opt
|
||||
self.values = context._cfgimpl_values
|
||||
self.multitype = multitype
|
||||
super(Multi, self).__init__(lst)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
|
|
Loading…
Reference in New Issue