settings are in a separate object
This commit is contained in:
parent
5969eaa2d6
commit
86f9096937
6 changed files with 143 additions and 164 deletions
|
@ -3,6 +3,7 @@ import autopath
|
|||
from py.test import raises
|
||||
from tiramisu.config import *
|
||||
from tiramisu.option import *
|
||||
from tiramisu.setting import settings
|
||||
|
||||
def make_description():
|
||||
gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
|
||||
|
@ -48,25 +49,6 @@ def make_description2():
|
|||
intoption, boolop])
|
||||
return descr
|
||||
|
||||
#def test_override_are_default_owner():
|
||||
# "config.override() implies that the owner is 'default' again"
|
||||
# descr = make_description2()
|
||||
# config = Config(descr)
|
||||
# config.bool = False
|
||||
# # default
|
||||
# assert config.gc._cfgimpl_value_owners['dummy'] == 'default'
|
||||
# # user
|
||||
# config.gc.dummy = True
|
||||
# assert config.gc._cfgimpl_value_owners['dummy'] == 'user'
|
||||
# assert config._cfgimpl_values['gc']._cfgimpl_value_owners['dummy'] == 'user'
|
||||
# #Options have an available default setting and can give it back
|
||||
# assert config._cfgimpl_descr._children[0]._children[1].getdefault() == False
|
||||
# config.override({'gc.dummy':True})
|
||||
# assert config.gc._cfgimpl_value_owners['dummy'] == 'default'
|
||||
# # user again
|
||||
# config.gc.dummy = False
|
||||
# assert config.gc._cfgimpl_value_owners['dummy'] == 'user'
|
||||
|
||||
def test_has_callback():
|
||||
descr = make_description()
|
||||
# here the owner is 'default'
|
||||
|
@ -74,7 +56,7 @@ def test_has_callback():
|
|||
config.bool = False
|
||||
# because dummy has a callback
|
||||
dummy = config.unwrap_from_path('gc.dummy')
|
||||
config.cfgimpl_freeze()
|
||||
settings.freeze()
|
||||
dummy.freeze()
|
||||
raises(TypeError, "config.gc.dummy = True")
|
||||
|
||||
|
@ -83,12 +65,7 @@ def test_freeze_and_has_callback_with_setoption():
|
|||
descr = make_description()
|
||||
config = Config(descr)
|
||||
config.bool = False
|
||||
config.cfgimpl_freeze()
|
||||
settings.freeze()
|
||||
dummy = config.unwrap_from_path('gc.dummy')
|
||||
dummy.freeze()
|
||||
raises(TypeError, "config.gc.setoption('dummy', True, 'gen_config')")
|
||||
|
||||
#def test_cannot_override():
|
||||
# descr = make_description()
|
||||
# config = Config(descr, bool=False)
|
||||
# raises(TypeError, "config.override({'gc.dummy': True})")
|
||||
|
|
|
@ -5,6 +5,7 @@ from py.test import raises
|
|||
|
||||
from tiramisu.config import *
|
||||
from tiramisu.option import *
|
||||
from tiramisu.setting import settings
|
||||
|
||||
def make_description():
|
||||
gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
|
||||
|
@ -74,7 +75,7 @@ def test_frozen_value():
|
|||
s = StrOption("string", "", default="string")
|
||||
descr = OptionDescription("options", "", [s])
|
||||
config = Config(descr)
|
||||
config.cfgimpl_freeze()
|
||||
settings.freeze()
|
||||
s.freeze()
|
||||
raises(TypeError, 'config.string = "egg"')
|
||||
|
||||
|
@ -82,7 +83,7 @@ def test_freeze():
|
|||
"freeze a whole configuration object"
|
||||
descr = make_description()
|
||||
conf = Config(descr)
|
||||
conf.cfgimpl_freeze()
|
||||
settings.freeze()
|
||||
name = conf.unwrap_from_path("gc.name")
|
||||
name.freeze()
|
||||
raises(TypeError, "conf.gc.name = 'framework'")
|
||||
|
@ -133,4 +134,3 @@ def test_with_many_subgroups():
|
|||
assert name == "booltwo"
|
||||
option = getattr(homeconfig._cfgimpl_descr, name)
|
||||
assert option._is_hidden()
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ from py.test import raises
|
|||
|
||||
from tiramisu.config import *
|
||||
from tiramisu.option import *
|
||||
from tiramisu.setting import settings
|
||||
|
||||
def make_description():
|
||||
gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
|
||||
|
@ -39,6 +40,6 @@ def test_root_config_answers_ok():
|
|||
boolop = BoolOption('boolop', 'Test boolean option op', default=True)
|
||||
descr = OptionDescription('tiramisu', '', [gcdummy, boolop])
|
||||
cfg = Config(descr)
|
||||
cfg.cfgimpl_enable_property('hiddend') #cfgimpl_hide()
|
||||
settings.enable_property('hiddend') #cfgimpl_hide()
|
||||
assert cfg.dummy == False
|
||||
assert cfg.boolop == True
|
||||
|
|
|
@ -26,23 +26,11 @@ from tiramisu.error import (PropertiesOptionError, ConfigError, NotFoundError,
|
|||
MandatoryError, MethodCallError, NoValueReturned)
|
||||
from tiramisu.option import (OptionDescription, Option, SymLinkOption,
|
||||
group_types, Multi, apply_requires)
|
||||
|
||||
# ______________________________________________________________________
|
||||
# generic owner. 'default' is the general config owner after init time
|
||||
default_owner = 'user'
|
||||
from tiramisu.setting import settings
|
||||
|
||||
# ____________________________________________________________
|
||||
class Config(object):
|
||||
"main configuration management entry"
|
||||
#properties attribute: the name of a property enables this property
|
||||
_cfgimpl_properties = ['hidden', 'disabled']
|
||||
_cfgimpl_permissive = []
|
||||
#mandatory means: a mandatory option has to have a value that is not None
|
||||
_cfgimpl_mandatory = True
|
||||
_cfgimpl_frozen = True
|
||||
#enables validation function for options if set
|
||||
_cfgimpl_validator = False
|
||||
_cfgimpl_owner = default_owner
|
||||
_cfgimpl_toplevel = None
|
||||
|
||||
def __init__(self, descr, parent=None):
|
||||
|
@ -62,7 +50,6 @@ class Config(object):
|
|||
self._cfgimpl_warnings = []
|
||||
self._cfgimpl_toplevel = self._cfgimpl_get_toplevel()
|
||||
'`freeze()` allows us to carry out this calculation again if necessary'
|
||||
self._cfgimpl_frozen = self._cfgimpl_toplevel._cfgimpl_frozen
|
||||
self._cfgimpl_build()
|
||||
|
||||
def _validate_duplicates(self, children):
|
||||
|
@ -100,11 +87,6 @@ class Config(object):
|
|||
self._cfgimpl_values[child._name] = Config(child, parent=self)
|
||||
# self.override(overrides)
|
||||
|
||||
def cfgimpl_set_permissive(self, permissive):
|
||||
if not isinstance(permissive, list):
|
||||
raise TypeError('permissive must be a list')
|
||||
self._cfgimpl_permissive = permissive
|
||||
|
||||
def cfgimpl_update(self):
|
||||
"""dynamically adds `Option()` or `OptionDescription()`
|
||||
"""
|
||||
|
@ -123,38 +105,6 @@ class Config(object):
|
|||
if child._name not in self._cfgimpl_values:
|
||||
self._cfgimpl_values[child._name] = Config(child, parent=self)
|
||||
|
||||
def cfgimpl_set_owner(self, owner):
|
||||
":param owner: sets the default value for owner at the Config level"
|
||||
self._cfgimpl_owner = owner
|
||||
for child in self._cfgimpl_descr._children:
|
||||
if isinstance(child, OptionDescription):
|
||||
self._cfgimpl_values[child._name].cfgimpl_set_owner(owner)
|
||||
# ____________________________________________________________
|
||||
# properties methods
|
||||
def _cfgimpl_has_properties(self):
|
||||
"has properties means the Config's properties attribute is not empty"
|
||||
return bool(len(self._cfgimpl_properties))
|
||||
|
||||
def _cfgimpl_has_property(self, propname):
|
||||
"""has property propname in the Config's properties attribute
|
||||
:param property: string wich is the name of the property"""
|
||||
return propname in self._cfgimpl_properties
|
||||
|
||||
def cfgimpl_enable_property(self, propname):
|
||||
"puts property propname in the Config's properties attribute"
|
||||
if self._cfgimpl_parent != None:
|
||||
raise MethodCallError("this method root_hide() shall not be"
|
||||
"used with non-root Config() object")
|
||||
if propname not in self._cfgimpl_properties:
|
||||
self._cfgimpl_properties.append(propname)
|
||||
|
||||
def cfgimpl_disable_property(self, propname):
|
||||
"deletes property propname in the Config's properties attribute"
|
||||
if self._cfgimpl_parent != None:
|
||||
raise MethodCallError("this method root_hide() shall not be"
|
||||
"used with non-root Config() object")
|
||||
if self._cfgimpl_has_property(propname):
|
||||
self._cfgimpl_properties.remove(propname)
|
||||
# ____________________________________________________________
|
||||
# attribute methods
|
||||
def __setattr__(self, name, value):
|
||||
|
@ -167,7 +117,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_owner)
|
||||
self.setoption(name, value, settings.owner)
|
||||
|
||||
def _validate(self, name, opt_or_descr, permissive=False):
|
||||
"validation for the setattr and the getattr"
|
||||
|
@ -177,10 +127,10 @@ class Config(object):
|
|||
raise TypeError('Unexpected object: {0}'.format(repr(opt_or_descr)))
|
||||
properties = copy(opt_or_descr.properties)
|
||||
for proper in copy(properties):
|
||||
if not self._cfgimpl_toplevel._cfgimpl_has_property(proper):
|
||||
if not settings.has_property(proper):
|
||||
properties.remove(proper)
|
||||
if permissive:
|
||||
for perm in self._cfgimpl_toplevel._cfgimpl_permissive:
|
||||
for perm in settings.permissive:
|
||||
if perm in properties:
|
||||
properties.remove(perm)
|
||||
if properties != []:
|
||||
|
@ -199,8 +149,7 @@ class Config(object):
|
|||
|
||||
def _test_mandatory(self, path, opt):
|
||||
# mandatory options
|
||||
homeconfig = self._cfgimpl_get_toplevel()
|
||||
mandatory = homeconfig._cfgimpl_mandatory
|
||||
mandatory = settings.mandatory
|
||||
if opt.is_mandatory() and mandatory:
|
||||
if self._is_empty(opt) and \
|
||||
opt.is_empty_by_default():
|
||||
|
@ -215,7 +164,7 @@ class Config(object):
|
|||
attribute notation mechanism for accessing the value of an option
|
||||
:param name: attribute name
|
||||
:param permissive: permissive doesn't raise some property error
|
||||
(see ``_cfgimpl_permissive``)
|
||||
(see ``settings.permissive``)
|
||||
:return: option's value if name is an option name, OptionDescription
|
||||
otherwise
|
||||
"""
|
||||
|
@ -250,9 +199,9 @@ class Config(object):
|
|||
return value
|
||||
else:
|
||||
return value
|
||||
rootconfig = self._cfgimpl_get_toplevel()
|
||||
try:
|
||||
result = opt_or_descr.getcallback_value(rootconfig)
|
||||
result = opt_or_descr.getcallback_value(
|
||||
self._cfgimpl_get_toplevel())
|
||||
except NoValueReturned, err:
|
||||
pass
|
||||
else:
|
||||
|
@ -267,7 +216,7 @@ class Config(object):
|
|||
' for option {0} : shall not be a list'.format(name))
|
||||
_result = result
|
||||
if _result != None and not opt_or_descr.validate(_result,
|
||||
rootconfig._cfgimpl_validator):
|
||||
settings.validator):
|
||||
raise ConfigError('invalid calculated value returned'
|
||||
' for option {0}'.format(name))
|
||||
self._cfgimpl_values[name] = _result
|
||||
|
@ -327,7 +276,7 @@ class Config(object):
|
|||
child = getattr(self._cfgimpl_descr, name)
|
||||
if type(child) != SymLinkOption:
|
||||
if who == None:
|
||||
who = self._cfgimpl_owner
|
||||
who = settings.owner
|
||||
if child.is_multi():
|
||||
if type(value) != Multi:
|
||||
if type(value) == list:
|
||||
|
@ -361,7 +310,7 @@ class Config(object):
|
|||
pass
|
||||
except Exception, e:
|
||||
raise e # HiddenOptionError or DisabledOptionError
|
||||
homeconfig.setoption(name, value, self._cfgimpl_owner)
|
||||
homeconfig.setoption(name, value, settings.owner)
|
||||
elif len(candidates) > 1:
|
||||
raise AmbigousOptionError(
|
||||
'more than one option that ends with %s' % (key, ))
|
||||
|
@ -433,64 +382,6 @@ class Config(object):
|
|||
"Config implements its own warning pile"
|
||||
return self._cfgimpl_get_toplevel()._cfgimpl_warnings
|
||||
# ____________________________________________________________
|
||||
# Config()'s status
|
||||
def cfgimpl_freeze(self):
|
||||
"cannot modify the frozen `Option`'s"
|
||||
rootconfig = self._cfgimpl_get_toplevel()
|
||||
rootconfig._cfgimpl_frozen = True
|
||||
self._cfgimpl_frozen = True
|
||||
|
||||
def cfgimpl_unfreeze(self):
|
||||
"can modify the Options that are frozen"
|
||||
rootconfig = self._cfgimpl_get_toplevel()
|
||||
rootconfig._cfgimpl_frozen = False
|
||||
self._cfgimpl_frozen = False
|
||||
|
||||
def is_frozen(self):
|
||||
"freeze flag at Config level"
|
||||
rootconfig = self._cfgimpl_get_toplevel()
|
||||
return rootconfig._cfgimpl_frozen
|
||||
|
||||
def cfgimpl_read_only(self):
|
||||
"convenience method to freeze, hidde and disable"
|
||||
self.cfgimpl_freeze()
|
||||
rootconfig = self._cfgimpl_get_toplevel()
|
||||
rootconfig.cfgimpl_disable_property('hidden')
|
||||
rootconfig.cfgimpl_enable_property('disabled')
|
||||
rootconfig._cfgimpl_mandatory = True
|
||||
rootconfig._cfgimpl_validator = True
|
||||
|
||||
def cfgimpl_read_write(self):
|
||||
"convenience method to freeze, hidde and disable"
|
||||
self.cfgimpl_freeze()
|
||||
rootconfig = self._cfgimpl_get_toplevel()
|
||||
rootconfig.cfgimpl_enable_property('hidden')
|
||||
rootconfig.cfgimpl_enable_property('disabled')
|
||||
rootconfig._cfgimpl_mandatory = False
|
||||
|
||||
def cfgimpl_non_mandatory(self):
|
||||
"""mandatory at the Config level means that the Config raises an error
|
||||
if a mandatory option is found"""
|
||||
if self._cfgimpl_parent != None:
|
||||
raise MethodCallError("this method root_mandatory shall"
|
||||
" not be used with non-root Confit() object")
|
||||
rootconfig = self._cfgimpl_get_toplevel()
|
||||
rootconfig._cfgimpl_mandatory = False
|
||||
|
||||
def cfgimpl_mandatory(self):
|
||||
"""mandatory at the Config level means that the Config raises an error
|
||||
if a mandatory option is found"""
|
||||
if self._cfgimpl_parent != None:
|
||||
raise MethodCallError("this method root_mandatory shall"
|
||||
" not be used with non-root Confit() object")
|
||||
rootconfig = self._cfgimpl_get_toplevel()
|
||||
rootconfig._cfgimpl_mandatory = True
|
||||
|
||||
def is_mandatory(self):
|
||||
"all mandatory Options shall have a value"
|
||||
rootconfig = self._cfgimpl_get_toplevel()
|
||||
return rootconfig._cfgimpl_mandatory
|
||||
# ____________________________________________________________
|
||||
def getkey(self):
|
||||
return self._cfgimpl_descr.getkey(self)
|
||||
|
||||
|
@ -685,8 +576,8 @@ def mandatory_warnings(config):
|
|||
|
||||
:returns: generator of mandatory Option's path
|
||||
"""
|
||||
mandatory = config._cfgimpl_get_toplevel()._cfgimpl_mandatory
|
||||
config._cfgimpl_get_toplevel()._cfgimpl_mandatory = True
|
||||
mandatory = settings.mandatory
|
||||
settings.mandatory = True
|
||||
for path in config._cfgimpl_descr.getpaths(include_groups=True):
|
||||
try:
|
||||
value = config._getattr(path, permissive=True)
|
||||
|
@ -694,4 +585,4 @@ def mandatory_warnings(config):
|
|||
yield path
|
||||
except PropertiesOptionError:
|
||||
pass
|
||||
config._cfgimpl_get_toplevel()._cfgimpl_mandatory = mandatory
|
||||
settings.mandatory = mandatory
|
||||
|
|
|
@ -26,6 +26,7 @@ from tiramisu.error import (ConfigError, ConflictConfigError, NotFoundError,
|
|||
RequiresError, RequirementRecursionError, MandatoryError,
|
||||
PropertiesOptionError)
|
||||
from tiramisu.autolib import carry_out_calculation
|
||||
from tiramisu.setting import settings
|
||||
|
||||
requires_actions = [('hide', 'show'), ('enable', 'disable'), ('freeze', 'unfreeze')]
|
||||
|
||||
|
@ -63,7 +64,7 @@ class Multi(list):
|
|||
|
||||
def setoption(self, value, key=None, who=None):
|
||||
if who is None:
|
||||
who = self.config._cfgimpl_owner
|
||||
who = settings.owner
|
||||
if value != None:
|
||||
if not self.child._validate(value):
|
||||
raise ConfigError("invalid value {0} "
|
||||
|
@ -78,7 +79,7 @@ class Multi(list):
|
|||
return ret
|
||||
|
||||
def pop(self, key):
|
||||
self.child.setowner(self.config, self.config._cfgimpl_owner)
|
||||
self.child.setowner(self.config, settings.owner)
|
||||
super(Multi, self).pop(key)
|
||||
# ____________________________________________________________
|
||||
#
|
||||
|
@ -257,7 +258,7 @@ class Option(HiddenBaseType, DisabledBaseType):
|
|||
:type who: string """
|
||||
name = self._name
|
||||
rootconfig = config._cfgimpl_get_toplevel()
|
||||
if not self.validate(value, rootconfig._cfgimpl_validator):
|
||||
if not self.validate(value, settings.validator):
|
||||
raise ConfigError('invalid value %s for option %s' % (value, name))
|
||||
if self.is_mandatory():
|
||||
# value shall not be '' for a mandatory option
|
||||
|
@ -266,14 +267,14 @@ class Option(HiddenBaseType, DisabledBaseType):
|
|||
value = None
|
||||
if self.is_multi() and '' in value:
|
||||
value = Multi([{'': None}.get(i, i) for i in value], config, self)
|
||||
if config.is_mandatory() and ((self.is_multi() and value == []) or \
|
||||
if settings.is_mandatory() and ((self.is_multi() and value == []) or \
|
||||
(not self.is_multi() and value is None)):
|
||||
raise MandatoryError('cannot change the value to %s for '
|
||||
'option %s' % (value, name))
|
||||
if name not in config._cfgimpl_values:
|
||||
raise AttributeError('unknown option %s' % (name))
|
||||
|
||||
if config.is_frozen() and self.is_frozen():
|
||||
if settings.is_frozen() and self.is_frozen():
|
||||
raise TypeError('cannot change the value to %s for '
|
||||
'option %s this option is frozen' % (str(value), name))
|
||||
apply_requires(self, config)
|
||||
|
|
109
tiramisu/setting.py
Normal file
109
tiramisu/setting.py
Normal file
|
@ -0,0 +1,109 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
"sets the options of the configuration objects Config object itself"
|
||||
# Copyright (C) 2012 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
|
||||
# the Free Software Foundation; either version 2 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 General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
# The original `Config` design model is unproudly borrowed from
|
||||
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
|
||||
# the whole pypy projet is under MIT licence
|
||||
# ____________________________________________________________
|
||||
|
||||
class Setting():
|
||||
"``Config()``'s configuration options"
|
||||
# properties attribute: the name of a property enables this property
|
||||
properties = ['hidden', 'disabled']
|
||||
# overrides the validations in the acces of the option values
|
||||
permissive = []
|
||||
# a mandatory option must have a value that is not None
|
||||
mandatory = True
|
||||
frozen = True
|
||||
# enables validation function for options if set
|
||||
validator = False
|
||||
# generic owner. 'default' is the general config owner after init time
|
||||
owner = 'user'
|
||||
# ____________________________________________________________
|
||||
# properties methods
|
||||
def has_properties(self):
|
||||
"has properties means the Config's properties attribute is not empty"
|
||||
return bool(len(self.properties))
|
||||
|
||||
def has_property(self, propname):
|
||||
"""has property propname in the Config's properties attribute
|
||||
:param property: string wich is the name of the property"""
|
||||
return propname in self.properties
|
||||
|
||||
def enable_property(self, propname):
|
||||
"puts property propname in the Config's properties attribute"
|
||||
if propname not in self.properties:
|
||||
self.properties.append(propname)
|
||||
|
||||
def disable_property(self, propname):
|
||||
"deletes property propname in the Config's properties attribute"
|
||||
if self.has_property(propname):
|
||||
self.properties.remove(propname)
|
||||
|
||||
def set_permissive(self, permissive):
|
||||
if not isinstance(permissive, list):
|
||||
raise TypeError('permissive must be a list')
|
||||
self.permissive = permissive
|
||||
|
||||
def read_only(self):
|
||||
"convenience method to freeze, hidde and disable"
|
||||
self.freeze()
|
||||
self.disable_property('hidden')
|
||||
self.enable_property('disabled')
|
||||
self.mandatory = True
|
||||
self.validator = True
|
||||
|
||||
def read_write(self):
|
||||
"convenience method to freeze, hidde and disable"
|
||||
self.freeze()
|
||||
self.enable_property('hidden')
|
||||
self.enable_property('disabled')
|
||||
self.mandatory = False
|
||||
|
||||
def non_mandatory(self):
|
||||
"""mandatory at the Config level means that the Config raises an error
|
||||
if a mandatory option is found"""
|
||||
self.mandatory = False
|
||||
|
||||
def mandatory(self):
|
||||
"""mandatory at the Config level means that the Config raises an error
|
||||
if a mandatory option is found"""
|
||||
self.mandatory = True
|
||||
|
||||
def is_mandatory(self):
|
||||
"all mandatory Options shall have a value"
|
||||
return self.mandatory
|
||||
|
||||
def freeze(self):
|
||||
"cannot modify the frozen `Option`'s"
|
||||
self.frozen = True
|
||||
|
||||
def unfreeze(self):
|
||||
"can modify the Options that are frozen"
|
||||
self.frozen = False
|
||||
|
||||
def is_frozen(self):
|
||||
"freeze flag at Config level"
|
||||
return self.frozen
|
||||
|
||||
def set_owner(self, owner):
|
||||
":param owner: sets the default value for owner at the Config level"
|
||||
self.owner = owner
|
||||
|
||||
# Setting is actually a singleton
|
||||
settings = Setting()
|
Loading…
Reference in a new issue