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)
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])
# -*- 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
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):
- 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):
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"
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):
"""
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)]
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, ))
"""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`
pass
class NoValueReturned(Exception):
pass
+class OptionValueError(Exception):
+ pass
# -*- 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
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')]
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):
"""
# 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)):
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):
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'):
# 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"
# -*- 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
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):
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)
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 \
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):