replace special_owner with hascallback_and_freeze

This commit is contained in:
gwen 2012-08-14 10:55:08 +02:00
parent 11b2edd07d
commit bf0dcbe2c8
6 changed files with 48 additions and 121 deletions

View File

@ -3,7 +3,6 @@ import autopath
from py.test import raises from py.test import raises
from tiramisu.config import * from tiramisu.config import *
from tiramisu.option import * from tiramisu.option import *
from tiramisu.error import SpecialOwnersError
def make_description(): def make_description():
gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref') gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
@ -67,65 +66,20 @@ def test_override_are_default_owner():
config.gc.dummy = False config.gc.dummy = False
assert config.gc._cfgimpl_value_owners['dummy'] == 'user' assert config.gc._cfgimpl_value_owners['dummy'] == 'user'
def test_change_owner(): def test_has_callback():
descr = make_description() descr = make_description()
# here the owner is 'default' # here the owner is 'default'
config = Config(descr, bool=False) config = Config(descr, bool=False)
# the default owner is 'user' (which is not 'default') # because dummy has a callback
# Still not getting it ? read the docs raises(ConflictConfigError, "config.gc.dummy = True")
config.gc.dummy = True
assert config.gc._cfgimpl_value_owners['dummy'] == 'user'
# config.cfgimpl_set_owner('eggs')
# config.set(dummy=False)
# assert config.gc._cfgimpl_value_owners['dummy'] == 'eggs'
# config.cfgimpl_set_owner('spam')
# gcdummy = config.unwrap_from_path('gc.dummy')
# gcdummy.setowner(config.gc, 'blabla')
# assert config.gc._cfgimpl_value_owners['dummy'] == 'blabla'
# config.gc.dummy = True
# assert config.gc._cfgimpl_value_owners['dummy'] == 'spam'
#____________________________________________________________ #____________________________________________________________
# special owners def test_has_callback_with_setoption():
def test_auto_owner():
descr = make_description() descr = make_description()
config = Config(descr, bool=False) config = Config(descr, bool=False)
config.gc.setoption('dummy', True, 'auto') raises(ConflictConfigError, "config.gc.setoption('dummy', True, 'gen_config')")
raises(PropertiesOptionError, "config.gc.dummy")
raises(ConflictConfigError, "config.gc.setoption('dummy', False, 'auto')")
# shall return an auto value...
#assert config.gc.dummy == 'auto_dummy_value'
def test_cannot_override_special_owners(): def test_cannot_override_special_owners():
descr = make_description() descr = make_description()
config = Config(descr, bool=False) config = Config(descr, bool=False)
config.gc.setoption('dummy', True, 'auto') raises(ConflictConfigError, "config.override({'gc.dummy': True})")
raises(SpecialOwnersError, "config.override({'gc.dummy': True})")
# FIXME have to test the fills anyway
#def test_fill_owner():
# "fill option"
# descr = make_description()
# config = Config(descr, bool=False)
# assert config.bool == False
# assert config.gc.dummy == False
# # 'fill' special values
# config.gc.setoption('dummy', True, 'fill')
# assert config.gc.dummy == False
#def test_auto_fill_and_override():
# descr = make_description()
# config = Config(descr, bool=False)
# booloption = config.unwrap_from_path('bool')
# booloption.callback = 'identical'
# booloption.setowner(config, 'auto')
# assert config.bool == 'identicalbool'
# gcdummy = config.unwrap_from_path('gc.dummy')
# gcdummy.callback = 'identical'
# gcdummy.setowner(config.gc, 'fill')
# raises(SpecialOwnersError, "config.override({'gc.dummy':True})")
# config.gc.setoption('dummy', False, 'fill')
# # value is returned
# assert config.gc.dummy == False

View File

@ -67,7 +67,7 @@ def test_freeze_one_option():
#freeze only one option #freeze only one option
conf.gc._cfgimpl_descr.dummy.freeze() conf.gc._cfgimpl_descr.dummy.freeze()
assert conf.gc.dummy == False assert conf.gc.dummy == False
raises(TypeError, "conf.gc.dummy = True") raises(ConflictConfigError, "conf.gc.dummy = True")
def test_frozen_value(): def test_frozen_value():
"setattr a frozen value at the config level" "setattr a frozen value at the config level"

View File

@ -19,18 +19,15 @@
# the whole pypy projet is under MIT licence # the whole pypy projet is under MIT licence
# ____________________________________________________________ # ____________________________________________________________
"enables us to carry out a calculation and return an option's value" "enables us to carry out a calculation and return an option's value"
from tiramisu.error import PropertiesOptionError, SpecialOwnersError from tiramisu.error import PropertiesOptionError, ConflictConfigError
# ____________________________________________________________ # ____________________________________________________________
# automatic Option object # automatic Option object
special_owners = ['auto', 'fill'] #def special_owner_factory(name, owner, value,
# callback, callback_params=None, config=None):
def special_owner_factory(name, owner, value, # # in case of an 'auto' and a 'fill' without a value,
callback, callback_params=None, config=None): # # we have to carry out a calculation
# in case of an 'auto' and a 'fill' without a value, # return calc_factory(name, callback, callback_params, config)
# we have to carry out a calculation def carry_out_calculation(name, callback, callback_params, config):
return calc_factory(name, callback, callback_params, config)
def calc_factory(name, callback, callback_params, config):
# FIXME we have to know the exact status of the config # FIXME we have to know the exact status of the config
# not to disrupt it # not to disrupt it
# config.freeze() # config.freeze()
@ -54,7 +51,7 @@ def calc_factory(name, callback, callback_params, config):
if opt_value != None: if opt_value != None:
len_value = len(opt_value) len_value = len(opt_value)
if len_multi != 0 and len_multi != len_value: if len_multi != 0 and len_multi != len_value:
raise SpecialOwnersError('unable to carry out a calculation, ' raise ConflictConfigError('unable to carry out a calculation, '
'option values with multi types must have same length for: ' 'option values with multi types must have same length for: '
+ name) + name)
len_multi = len_value len_multi = len_value
@ -89,6 +86,6 @@ def calculate(name, callback, tcparams):
except AttributeError, err: except AttributeError, err:
import traceback import traceback
traceback.print_exc() traceback.print_exc()
raise SpecialOwnersError("callback: {0} return error {1} for " raise ConflictConfigError("callback: {0} return error {1} for "
"option: {2}".format(callback, str(err), name)) "option: {2}".format(callback, str(err), name))

View File

@ -23,10 +23,10 @@
from copy import copy from copy import copy
from tiramisu.error import (PropertiesOptionError, ConfigError, NotFoundError, from tiramisu.error import (PropertiesOptionError, ConfigError, NotFoundError,
AmbigousOptionError, ConflictConfigError, NoMatchingOptionFound, AmbigousOptionError, ConflictConfigError, NoMatchingOptionFound,
SpecialOwnersError, MandatoryError, MethodCallError) MandatoryError, MethodCallError)
from tiramisu.option import (OptionDescription, Option, SymLinkOption, from tiramisu.option import (OptionDescription, Option, SymLinkOption,
group_types, Multi, apply_requires) group_types, Multi, apply_requires)
from tiramisu.autolib import special_owners, special_owner_factory from tiramisu.autolib import carry_out_calculation
# ______________________________________________________________________ # ______________________________________________________________________
# generic owner. 'default' is the general config owner after init time # generic owner. 'default' is the general config owner after init time
default_owner = 'user' default_owner = 'user'
@ -70,20 +70,12 @@ class Config(object):
child=child) child=child)
self._cfgimpl_values[child._name] = childdef self._cfgimpl_values[child._name] = childdef
self._cfgimpl_previous_values[child._name] = list(childdef) self._cfgimpl_previous_values[child._name] = list(childdef)
self._cfgimpl_value_owners[child._name] = ['default' \
for i in range(len(child.getdefault() ))]
else: else:
childdef = child.getdefault() childdef = child.getdefault()
self._cfgimpl_values[child._name] = childdef self._cfgimpl_values[child._name] = childdef
self._cfgimpl_previous_values[child._name] = childdef self._cfgimpl_previous_values[child._name] = childdef
if child.getcallback() is not None:
if child._is_hidden():
self._cfgimpl_value_owners[child._name] = 'auto'
else:
self._cfgimpl_value_owners[child._name] = 'fill'
else:
if child.is_multi():
self._cfgimpl_value_owners[child._name] = ['default' \
for i in range(len(child.getdefault() ))]
else:
self._cfgimpl_value_owners[child._name] = 'default' self._cfgimpl_value_owners[child._name] = 'default'
elif isinstance(child, OptionDescription): elif isinstance(child, OptionDescription):
self._validate_duplicates(child._children) self._validate_duplicates(child._children)
@ -113,10 +105,6 @@ class Config(object):
def override(self, overrides): def override(self, overrides):
for name, value in overrides.iteritems(): for name, value in overrides.iteritems():
homeconfig, name = self._cfgimpl_get_home_by_path(name) homeconfig, name = self._cfgimpl_get_home_by_path(name)
# if there are special_owners, impossible to override
if homeconfig._cfgimpl_value_owners[name] in special_owners:
raise SpecialOwnersError("cannot override option: {0} because "
"of its special owner".format(name))
homeconfig.setoption(name, value, 'default') homeconfig.setoption(name, value, 'default')
def cfgimpl_set_owner(self, owner): def cfgimpl_set_owner(self, owner):
@ -209,19 +197,17 @@ class Config(object):
if name not in self._cfgimpl_values: if name not in self._cfgimpl_values:
raise AttributeError("%s object has no attribute %s" % raise AttributeError("%s object has no attribute %s" %
(self.__class__, name)) (self.__class__, name))
if name in self._cfgimpl_value_owners: if not isinstance(opt_or_descr, OptionDescription):
owner = self._cfgimpl_value_owners[name] # options with callbacks (fill or auto)
if owner in special_owners: if opt_or_descr.has_callback():
value = self._cfgimpl_values[name] value = self._cfgimpl_values[name]
if value != None: if value != None:
if opt_or_descr.is_multi(): if opt_or_descr.is_multi():
if owner == 'fill' and None not in value: if None not in value:
return value return value
else: else:
if owner == 'fill' and value != None:
return value return value
result = special_owner_factory(name, owner, result = carry_out_calculation(name,
value=value,
callback=opt_or_descr.getcallback(), callback=opt_or_descr.getcallback(),
callback_params=opt_or_descr.getcallback_params(), callback_params=opt_or_descr.getcallback_params(),
config=self._cfgimpl_get_toplevel()) config=self._cfgimpl_get_toplevel())
@ -245,7 +231,7 @@ class Config(object):
else: else:
_result = result _result = result
return _result return _result
if not isinstance(opt_or_descr, OptionDescription):
# mandatory options # mandatory options
homeconfig = self._cfgimpl_get_toplevel() homeconfig = self._cfgimpl_get_toplevel()
mandatory = homeconfig._cfgimpl_mandatory mandatory = homeconfig._cfgimpl_mandatory
@ -318,23 +304,19 @@ class Config(object):
else: else:
newowner = who newowner = who
if type(child) != SymLinkOption: if type(child) != SymLinkOption:
if child.is_mandatory() and value is None:
raise MandatoryError('cannot override value to %s for '
'option %s' % (value, name))
if name not in self._cfgimpl_values: if name not in self._cfgimpl_values:
raise AttributeError('unknown option %s' % (name,)) raise AttributeError('unknown option %s' % (name,))
# special owners, a value with a owner *auto* cannot be changed if child.has_callback() or child.isfrozen():
oldowner = self._cfgimpl_value_owners[child._name]
if oldowner == 'auto':
if who == 'auto':
raise ConflictConfigError('cannot override value to %s for ' raise ConflictConfigError('cannot override value to %s for '
'option %s' % (value, name)) 'option %s' % (value, name))
if oldowner == who: # if oldowner == who:
oldvalue = getattr(self, name) # oldvalue = getattr(self, name)
if oldvalue == value: #or who in ("default",): # if oldvalue == value:
return # return
child.setoption(self, value, who) child.setoption(self, value, who)
# if the value owner is 'auto', set the option to hidden
if who == 'auto':
if not child._is_hidden():
child.hide()
if (value is None and who != 'default' and not child.is_multi()): if (value is None and who != 'default' and not child.is_multi()):
child.setowner(self, 'default') child.setowner(self, 'default')
self._cfgimpl_values[name] = copy(child.getdefault()) self._cfgimpl_values[name] = copy(child.getdefault())

View File

@ -18,6 +18,4 @@ class RequirementRecursionError(RequiresError):
pass pass
class MandatoryError(Exception): class MandatoryError(Exception):
pass pass
class SpecialOwnersError(Exception):
pass

View File

@ -20,18 +20,17 @@
# the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/ # the rough pypy's guys: http://codespeak.net/svn/pypy/dist/pypy/config/
# the whole pypy projet is under MIT licence # the whole pypy projet is under MIT licence
# ____________________________________________________________ # ____________________________________________________________
from tiramisu.autolib import special_owners
from tiramisu.basetype import HiddenBaseType, DisabledBaseType from tiramisu.basetype import HiddenBaseType, DisabledBaseType
from tiramisu.error import (ConfigError, ConflictConfigError, NotFoundError, from tiramisu.error import (ConfigError, ConflictConfigError, NotFoundError,
SpecialOwnersError, RequiresError, RequirementRecursionError) RequiresError, RequirementRecursionError)
available_actions = ['hide', 'show', 'enable', 'disable'] available_actions = ['hide', 'show', 'enable', 'disable']
reverse_actions = {'hide': 'show', 'show': 'hide', reverse_actions = {'hide': 'show', 'show': 'hide',
'disable':'enable', 'enable': 'disable'} 'disable':'enable', 'enable': 'disable'}
# ____________________________________________________________ # ____________________________________________________________
# OptionDescription authorized group_type values # OptionDescription authorized group_type values
group_types = ['default', 'family', 'group', 'master'] group_types = ['default', 'family', 'group', 'master']
# ____________________________________________________________
# multi types # multi types
class Multi(list): class Multi(list):
"container that support items for the values of list (multi) options" "container that support items for the values of list (multi) options"
def __init__(self, lst, config, child): def __init__(self, lst, config, child):
@ -145,11 +144,11 @@ class Option(HiddenBaseType, DisabledBaseType):
def force_default(self): def force_default(self):
self._force_default_on_freeze = True self._force_default_on_freeze = True
def hascallback_and_isfrozen():
return self._frozen and self.has_callback()
def is_forced_on_freeze(self): def is_forced_on_freeze(self):
if self._frozen and self._force_default_on_freeze: return self._frozen and self._force_default_on_freeze
return True
else:
return False
def getdoc(self): def getdoc(self):
return self.doc return self.doc
@ -172,10 +171,6 @@ class Option(HiddenBaseType, DisabledBaseType):
name = self._name name = self._name
if self._frozen: if self._frozen:
raise TypeError("trying to change a frozen option's owner: %s" % name) raise TypeError("trying to change a frozen option's owner: %s" % name)
if owner in special_owners:
if self.callback == None:
raise SpecialOwnersError("no callback specified for"
"option {0}".format(name))
if self.is_multi(): if self.is_multi():
if not type(owner) == list: if not type(owner) == list:
raise ConfigError("invalid owner for multi " raise ConfigError("invalid owner for multi "
@ -228,13 +223,16 @@ class Option(HiddenBaseType, DisabledBaseType):
def getkey(self, value): def getkey(self, value):
return value return value
# ____________________________________________________________
def freeze(self): def freeze(self):
self._frozen = True self._frozen = True
return True return True
def unfreeze(self): def unfreeze(self):
self._frozen = False self._frozen = False
def isfrozen(self):
return self._frozen
# ____________________________________________________________ # ____________________________________________________________
def is_multi(self): def is_multi(self):
return self.multi return self.multi
@ -513,8 +511,6 @@ def apply_requires(opt, config):
"detected for option: '{0}' with requirement on: '{1}'".format(path, name)) "detected for option: '{0}' with requirement on: '{1}'".format(path, name))
homeconfig, shortname = \ homeconfig, shortname = \
rootconfig._cfgimpl_get_home_by_path(name) rootconfig._cfgimpl_get_home_by_path(name)
# FIXME: doesn't work with 'auto' or 'fill' yet
# (copy the code from the __getattr__
if shortname in homeconfig._cfgimpl_values: if shortname in homeconfig._cfgimpl_values:
value = homeconfig._cfgimpl_values[shortname] value = homeconfig._cfgimpl_values[shortname]
if (not inverted and value == expected) or \ if (not inverted and value == expected) or \