values are in value objects now

This commit is contained in:
gwen 2013-02-07 16:20:21 +01:00
parent 29914051e0
commit 9259a6e3f7
13 changed files with 303 additions and 234 deletions

View file

@ -89,13 +89,13 @@ def test_base_config_in_a_tree():
assert config.gc.name == 'ref'
config.wantframework = True
def test_config_values():
"_cfgimpl_values appears to be a simple dict"
descr = make_description()
config = Config(descr)
config.bool = False
config.set(dummy=False)
assert config.gc._cfgimpl_values == {'dummy': False, 'float': 2.3, 'name': 'ref'}
#def test_config_values():
# "_cfgimpl_values appears to be a simple dict"
# descr = make_description()
# config = Config(descr)
# config.bool = False
# config.set(dummy=False)
# assert config.gc._cfgimpl_values == {'dummy': False, 'float': 2.3, 'name': 'ref'}
def test_cfgimpl_get_home_by_path():
descr = make_description()

View file

@ -3,7 +3,6 @@ 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')
@ -126,14 +125,14 @@ def test_newoption_add_in_subdescr():
config.bool = False
assert config.gc.newoption == False
def test_newoption_add_in_config():
descr = make_description()
config = Config(descr)
config.bool = False
newoption = BoolOption('newoption', 'dummy twoo', default=False)
descr.add_child(newoption)
config.cfgimpl_update()
assert config.newoption == False
#def test_newoption_add_in_config():
# descr = make_description()
# config = Config(descr)
# config.bool = False
# newoption = BoolOption('newoption', 'dummy twoo', default=False)
# descr.add_child(newoption)
# config.cfgimpl_update()
# assert config.newoption == False
# ____________________________________________________________
def make_description_requires():
gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
@ -236,6 +235,7 @@ def test_has_callback():
config.bool = False
# because dummy has a callback
dummy = config.unwrap_from_path('gc.dummy')
settings = config.cfgimpl_get_settings()
settings.freeze()
dummy.freeze()
raises(TypeError, "config.gc.dummy = True")
@ -244,6 +244,7 @@ def test_freeze_and_has_callback_with_setoption():
descr = make_description_callback()
config = Config(descr)
config.bool = False
settings = config.cfgimpl_get_settings()
settings.freeze()
dummy = config.unwrap_from_path('gc.dummy')
dummy.freeze()

View file

@ -79,18 +79,18 @@ def test_force_default_on_freeze():
assert config.dummy1 == False
assert config.dummy2 == False
def test_override_are_defaults():
descr = make_description()
config = Config(descr)
config.bool = False
config.gc.dummy = True
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.dummy == True
#assert config._cfgimpl_descr._children[0]._children[1].getdefault() == True
#assert config._cfgimpl_values['gc']._cfgimpl_value_owners['dummy'] == 'default'
#def test_override_are_defaults():
# descr = make_description()
# config = Config(descr)
# config.bool = False
# config.gc.dummy = True
# assert config._cfgimpl_values['gc']._cfgimpl_values.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.dummy == True
# #assert config._cfgimpl_descr._children[0]._children[1].getdefault() == True
# #assert config._cfgimpl_values['gc']._cfgimpl_value_owners['dummy'] == 'default'
def test_overrides_changes_option_value():
"with config.override(), the default is changed and the value is changed"

View file

@ -3,7 +3,7 @@ import autopath
from py.test import raises
from tiramisu.config import *
from tiramisu.option import *
from tiramisu.setting import settings, owners
from tiramisu.setting import owners
def make_description():
gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')

View file

@ -51,10 +51,10 @@ def test_reset():
config = Config(descr)
config.string = "foo"
assert config.string == "foo"
assert config._cfgimpl_value_owners['string'] == owners.user
assert config._cfgimpl_values.owners[s] == owners.user
config.unwrap_from_path("string").reset(config)
assert config.string == 'string'
assert config._cfgimpl_value_owners['string'] == owners.default
assert config._cfgimpl_values.owners[s] == owners.default
def test_reset_with_multi():
s = StrOption("string", "", default=["string"], default_multi="string" , multi=True)
@ -63,13 +63,13 @@ def test_reset_with_multi():
# config.string = []
config.unwrap_from_path("string").reset(config)
assert config.string == ["string"]
assert config._cfgimpl_value_owners['string'] == 'default'
assert config._cfgimpl_values.owners[s] == 'default'
config.string = ["eggs", "spam", "foo"]
assert config._cfgimpl_value_owners['string'] == 'user'
assert config._cfgimpl_values.owners[s] == 'user'
config.string = []
config.unwrap_from_path("string").reset(config)
# assert config.string == ["string"]
assert config._cfgimpl_value_owners['string'] == 'default'
assert config._cfgimpl_values.owners[s] == 'default'
raises(ConfigError, "config.string = None")
def test_default_with_multi():
@ -111,10 +111,10 @@ def test_access_with_multi_default():
s = StrOption("string", "", default=["string"], multi=True)
descr = OptionDescription("options", "", [s])
config = Config(descr)
assert config._cfgimpl_value_owners["string"] == 'default'
assert config._cfgimpl_values.owners[s] == 'default'
config.string = ["foo", "bar"]
assert config.string == ["foo", "bar"]
assert config._cfgimpl_value_owners["string"] == 'user'
assert config._cfgimpl_values.owners[s] == 'user'
#def test_attribute_access_with_multi2():
# s = StrOption("string", "", default="string", multi=True)
@ -227,7 +227,7 @@ def test_multi_with_bool():
config = Config(descr)
assert descr.bool.multi == True
config.bool = [True, False]
assert config._cfgimpl_values['bool'] == [True, False]
assert config._cfgimpl_context._cfgimpl_values[s] == [True, False]
assert config.bool == [True, False]
def test_multi_with_bool_two():
@ -323,22 +323,22 @@ def test_set_symlink_option():
assert config.s1.b == False
assert config.c == False
#____________________________________________________________
def test_config_impl_values():
descr = make_description()
config = Config(descr)
config.bool = False
# gcdummy.setoption(config, True, "user")
# config.setoption("gc.dummy", True, "user")
#config.gc.dummy = True
# config.setoption("bool", False, "user")
config.set(dummy=False)
assert config.gc._cfgimpl_values == {'dummy': False, 'float': 2.3, 'name': 'ref'}
## acces to the option object
# config.gc._cfgimpl_descr.dummy.setoption(config, True, "user")
assert config.gc.dummy == False
# config.set(dummy=True)
# assert config.gc.dummy == True
##____________________________________________________________
#def test_config_impl_values():
# descr = make_description()
# config = Config(descr)
# config.bool = False
## gcdummy.setoption(config, True, "user")
## config.setoption("gc.dummy", True, "user")
# #config.gc.dummy = True
## config.setoption("bool", False, "user")
# config.set(dummy=False)
# assert config.gc._cfgimpl_context._cfgimpl_values.values == {'dummy': False, 'float': 2.3, 'name': 'ref'}
# ## acces to the option object
## config.gc._cfgimpl_descr.dummy.setoption(config, True, "user")
# assert config.gc.dummy == False
## config.set(dummy=True)
## assert config.gc.dummy == True
#____________________________________________________________
def test_accepts_multiple_changes_from_option():

View file

@ -5,7 +5,6 @@ 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')
@ -64,6 +63,7 @@ def make_description_freeze():
def test_freeze_whole_config():
descr = make_description_freeze()
conf = Config(descr)
settings = conf.cfgimpl_get_settings()
settings.freeze_everything()
assert conf.gc.dummy == False
raises(TypeError, "conf.gc.dummy = True")
@ -85,6 +85,7 @@ def test_frozen_value():
s = StrOption("string", "", default="string")
descr = OptionDescription("options", "", [s])
config = Config(descr)
settings = config.cfgimpl_get_settings()
settings.freeze()
s.freeze()
raises(TypeError, 'config.string = "egg"')
@ -93,6 +94,7 @@ def test_freeze():
"freeze a whole configuration object"
descr = make_description()
conf = Config(descr)
settings = conf.cfgimpl_get_settings()
settings.freeze()
name = conf.unwrap_from_path("gc.name")
name.freeze()
@ -107,9 +109,8 @@ def test_is_hidden():
# getattr
raises(PropertiesOptionError, "config.gc.dummy")
# I want to access to this option anyway
path = 'gc.dummy'
homeconfig, name = config._cfgimpl_get_home_by_path(path)
assert homeconfig._cfgimpl_values[name] == False
opt = config.unwrap_from_path("gc.dummy")
assert config._cfgimpl_context._cfgimpl_values[opt] == False
def test_group_is_hidden():
descr = make_description()

View file

@ -4,7 +4,6 @@ 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')
@ -40,6 +39,7 @@ def test_root_config_answers_ok():
boolop = BoolOption('boolop', 'Test boolean option op', default=True)
descr = OptionDescription('tiramisu', '', [gcdummy, boolop])
cfg = Config(descr)
settings = cfg.cfgimpl_get_settings()
settings.enable_property('hiddend') #cfgimpl_hide()
assert cfg.dummy == False
assert cfg.boolop == True

View file

@ -1,7 +1,7 @@
import autopath
from py.test import raises
#import autopath
#from py.test import raises
from tool import reverse_from_paths
#from tool import reverse_from_paths
#def make_description():
# gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
@ -24,15 +24,15 @@ from tool import reverse_from_paths
# intoption, boolop])
# return descr
def test_rebuild():
# pouvoir faire une comparaison avec equal
d = {"s1.s2.s3.s4.a": True, "int": 43, "s2.b":True, "s3.c": True, "s3.d":[1,2,3]}
cfg = reverse_from_paths(d)
assert cfg.s1.s2.s3.s4.a == True
assert cfg.int == 43
assert cfg.s2.b == True
assert cfg.s3.c == True
assert cfg.s3.d == [1,2,3]
#def test_rebuild():
# # pouvoir faire une comparaison avec equal
# d = {"s1.s2.s3.s4.a": True, "int": 43, "s2.b":True, "s3.c": True, "s3.d":[1,2,3]}
# cfg = reverse_from_paths(d)
# assert cfg.s1.s2.s3.s4.a == True
# assert cfg.int == 43
# assert cfg.s2.b == True
# assert cfg.s3.c == True
# assert cfg.s3.d == [1,2,3]
# assert config.getpaths() == ['gc.name', 'gc.dummy', 'gc.float', 'bool',
# 'objspace', 'wantref', 'str', 'wantframework',

View file

@ -26,31 +26,50 @@ from tiramisu.error import (PropertiesOptionError, ConfigError, NotFoundError,
MandatoryError, MethodCallError, NoValueReturned)
from tiramisu.option import (OptionDescription, Option, SymLinkOption,
Multi, apply_requires)
from tiramisu.setting import settings, groups, owners
from tiramisu.setting import groups, owners, Setting
from tiramisu.value import OptionValues
# ____________________________________________________________
class Config(object):
"main configuration management entry"
_cfgimpl_toplevel = None
def __init__(self, descr, parent=None):
def __init__(self, descr, parent=None, context=None):
""" Configuration option management master class
:param descr: describes the configuration schema
:type descr: an instance of ``option.OptionDescription``
:param parent: is None if the ``Config`` is root parent Config otherwise
:type parent: ``Config``
:param context: the current root config
:type context: `Config`
"""
self._cfgimpl_descr = descr
self._cfgimpl_value_owners = {}
self._cfgimpl_parent = parent
"`Config()` indeed is in charge of the `Option()`'s values"
self._cfgimpl_values = {}
self._cfgimpl_previous_values = {}
if parent == None:
self._cfgimpl_settings = Setting()
self._cfgimpl_values = OptionValues()
else:
if context is None:
raise ConfigError("cannot find a value for this config")
self._cfgimpl_settings = None
self._cfgimpl_values = None
if context is None:
self._cfgimpl_context = self
else:
self._cfgimpl_context = context
"warnings are a great idea, let's make up a better use of it"
self._cfgimpl_warnings = []
self._cfgimpl_toplevel = self._cfgimpl_get_toplevel()
self._cfgimpl_build()
def cfgimpl_get_settings(self):
return self._cfgimpl_context._cfgimpl_settings
def cfgimpl_set_settings(self, settings):
if not isinstance(settings, Setting):
raise ConfigError("setting not allowed")
self._cfgimpl_context._cfgimpl_settings = settings
def _validate_duplicates(self, children):
"""duplicates Option names in the schema
:type children: list of `Option` or `OptionDescription`
@ -77,34 +96,35 @@ class Config(object):
childdef = Multi(copy(child.getdefault()), config=self,
opt=child)
max_len_child = max(max_len_child, len(childdef))
self._cfgimpl_values[child._name] = childdef
self._cfgimpl_previous_values[child._name] = list(childdef)
self._cfgimpl_context._cfgimpl_values[child] = childdef
self._cfgimpl_context._cfgimpl_values.previous_values[child] = list(childdef)
else:
childdef = child.getdefault()
self._cfgimpl_values[child._name] = childdef
self._cfgimpl_previous_values[child._name] = childdef
self._cfgimpl_context._cfgimpl_values[child] = childdef
self._cfgimpl_context._cfgimpl_values.previous_values[child] = childdef
child.setowner(self, owners.default)
elif isinstance(child, OptionDescription):
self._validate_duplicates(child._children)
self._cfgimpl_values[child._name] = Config(child, parent=self)
self._cfgimpl_context._cfgimpl_values[child] = Config(child, parent=self,
context=self._cfgimpl_context)
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)
# 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)
# ____________________________________________________________
# attribute methods
@ -118,7 +138,8 @@ 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, settings.get_owner())
self.setoption(name, value,
self._cfgimpl_context._cfgimpl_settings.get_owner())
def _validate(self, name, opt_or_descr, permissive=False):
"validation for the setattr and the getattr"
@ -128,10 +149,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 settings.has_property(proper):
if not self._cfgimpl_context._cfgimpl_settings.has_property(proper):
properties.remove(proper)
if permissive:
for perm in settings.permissive:
for perm in self._cfgimpl_context._cfgimpl_settings.permissive:
if perm in properties:
properties.remove(perm)
if properties != []:
@ -142,15 +163,15 @@ class Config(object):
def _is_empty(self, opt):
"convenience method to know if an option is empty"
if (not opt.is_multi() and self._cfgimpl_values[opt._name] == None) or \
(opt.is_multi() and (self._cfgimpl_values[opt._name] == [] or \
None in self._cfgimpl_values[opt._name])):
if (not opt.is_multi() and self._cfgimpl_context._cfgimpl_values[opt] == None) or \
(opt.is_multi() and (self._cfgimpl_context._cfgimpl_values[opt] == [] or \
None in self._cfgimpl_context._cfgimpl_values[opt])):
return True
return False
def _test_mandatory(self, path, opt):
# mandatory options
mandatory = settings.mandatory
mandatory = self._cfgimpl_context._cfgimpl_settings.mandatory
if opt.is_mandatory() and mandatory:
if self._is_empty(opt) and \
opt.is_empty_by_default():
@ -160,10 +181,11 @@ class Config(object):
def __getattr__(self, name):
return self._getattr(name)
def fill_multi(self, name, result, use_default_multi=False, default_multi=None):
def fill_multi(self, opt, result, use_default_multi=False, default_multi=None):
"""fills a multi option with default and calculated values
"""
value = self._cfgimpl_values[name]
# FIXME C'EST ENCORE DU N'IMPORTE QUOI
value = self._cfgimpl_context._cfgimpl_values[opt]
if not isinstance(result, list):
_result = [result]
else:
@ -175,7 +197,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 ``settings.permissive``)
(see ``permissive``)
:return: option's value if name is an option name, OptionDescription
otherwise
"""
@ -189,7 +211,7 @@ class Config(object):
if type(opt_or_descr) == SymLinkOption:
rootconfig = self._cfgimpl_get_toplevel()
return getattr(rootconfig, opt_or_descr.path)
if name not in self._cfgimpl_values:
if opt_or_descr not in self._cfgimpl_context._cfgimpl_values:
raise AttributeError("%s object has no attribute %s" %
(self.__class__, name))
self._validate(name, opt_or_descr, permissive)
@ -202,7 +224,7 @@ class Config(object):
if not isinstance(opt_or_descr, OptionDescription):
# options with callbacks
if opt_or_descr.has_callback():
value = self._cfgimpl_values[name]
value = self._cfgimpl_context._cfgimpl_values[opt_or_descr]
if (not opt_or_descr.is_frozen() or \
not opt_or_descr.is_forced_on_freeze()) and \
not opt_or_descr.is_default_owner(self):
@ -214,7 +236,7 @@ class Config(object):
pass
else:
if opt_or_descr.is_multi():
_result = self.fill_multi(name, result)
_result = self.fill_multi(opt_or_descr, result)
else:
# this result **shall not** be a list
if isinstance(result, list):
@ -222,22 +244,22 @@ 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,
settings.validator):
self._cfgimpl_context._cfgimpl_settings.validator):
raise ConfigError('invalid calculated value returned'
' for option {0}'.format(name))
self._cfgimpl_values[name] = _result
self._cfgimpl_context._cfgimpl_values[opt_or_descr] = _result
opt_or_descr.setowner(self, owners.default)
# frozen and force default
if not opt_or_descr.has_callback() and opt_or_descr.is_forced_on_freeze():
value = opt_or_descr.getdefault()
if opt_or_descr.is_multi():
value = self.fill_multi(name, value,
value = self.fill_multi(opt_or_descr, value,
use_default_multi=True,
default_multi=opt_or_descr.getdefault_multi())
self._cfgimpl_values[name] = value
self._cfgimpl_context._cfgimpl_values[opt_or_descr] = value
opt_or_descr.setowner(self, owners.default)
self._test_mandatory(name, opt_or_descr)
value = self._cfgimpl_values[name]
value = self._cfgimpl_context._cfgimpl_values[opt_or_descr]
return value
def unwrap_from_name(self, name):
@ -274,7 +296,7 @@ class Config(object):
child = getattr(self._cfgimpl_descr, name)
if type(child) != SymLinkOption:
if who == None:
who = settings.owner
who = self._cfgimpl_context._cfgimpl_settings.owner
if child.is_multi():
if not isinstance(who, owners.DefaultOwner):
if type(value) != Multi:
@ -284,7 +306,7 @@ class Config(object):
raise ConfigError("invalid value for option:"
" {0} that is set to multi".format(name))
else:
value = self.fill_multi(name, child.getdefault(),
value = self.fill_multi(child, child.getdefault(),
use_default_multi=True,
default_multi=child.getdefault_multi())
if not isinstance(who, owners.Owner):
@ -316,7 +338,8 @@ class Config(object):
pass
except Exception, e:
raise e # HiddenOptionError or DisabledOptionError
homeconfig.setoption(name, value, settings.get_owner())
homeconfig.setoption(name, value,
self._cfgimpl_context._cfgimpl_settings.get_owner())
elif len(candidates) > 1:
raise AmbigousOptionError(
'more than one option that ends with %s' % (key, ))
@ -371,14 +394,15 @@ class Config(object):
obj = obj._cfgimpl_parent
return ".".join(subpath)
# ______________________________________________________________________
def cfgimpl_previous_value(self, path):
"stores the previous value"
home, name = self._cfgimpl_get_home_by_path(path)
return home._cfgimpl_previous_values[name]
# def cfgimpl_previous_value(self, path):
# "stores the previous value"
# home, name = self._cfgimpl_get_home_by_path(path)
# # FIXME fucking name
# return home._cfgimpl_context._cfgimpl_values.previous_values[name]
def get_previous_value(self, name):
"for the time being, only the previous Option's value is accessible"
return self._cfgimpl_previous_values[name]
# def get_previous_value(self, name):
# "for the time being, only the previous Option's value is accessible"
# return self._cfgimpl_context._cfgimpl_values.previous_values[name]
# ______________________________________________________________________
def add_warning(self, warning):
"Config implements its own warning pile. Could be useful"
@ -420,7 +444,7 @@ class Config(object):
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
`settings.groups`
`setting.groups`
"""
if group_type is not None:
@ -592,9 +616,10 @@ def mandatory_warnings(config):
where no value has been set
:returns: generator of mandatory Option's path
FIXME : CAREFULL : not multi-user
"""
mandatory = settings.mandatory
settings.mandatory = True
mandatory = config._cfgimpl_context._cfgimpl_settings.mandatory
config._cfgimpl_context._cfgimpl_settings.mandatory = True
for path in config._cfgimpl_descr.getpaths(include_groups=True):
try:
value = config._getattr(path, permissive=True)
@ -602,4 +627,4 @@ def mandatory_warnings(config):
yield path
except PropertiesOptionError:
pass
settings.mandatory = mandatory
config._cfgimpl_context._cfgimpl_settings.mandatory = mandatory

View file

@ -26,7 +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, groups, owners
from tiramisu.setting import groups, owners
requires_actions = [('hide', 'show'), ('enable', 'disable'), ('freeze', 'unfreeze')]
@ -53,13 +53,15 @@ class Multi(list):
super(Multi, self).__init__(lst)
def __setitem__(self, key, value):
self._setvalue(value, key, who=settings.get_owner())
self._setvalue(value, key,
who=self.config._cfgimpl_context._cfgimpl_settings.get_owner())
def append(self, value):
"""the list value can be updated (appened)
only if the option is a master
"""
self._setvalue(value, who=settings.get_owner())
self._setvalue(value,
who=self.config._cfgimpl_context._cfgimpl_settings.get_owner())
def _setvalue(self, value, key=None, who=None):
if value != None:
@ -76,7 +78,7 @@ class Multi(list):
raise TypeError("invalid owner {0} for the value {1}".format(
str(who), str(value)))
self.opt.setowner(self.config, getattr(owners, who))
self.config._cfgimpl_previous_values[self.opt._name] = oldvalue
self.config._cfgimpl_context._cfgimpl_values.previous_values[self.opt] = oldvalue
def pop(self, key):
"""the list value can be updated (poped)
@ -86,8 +88,9 @@ class Multi(list):
:return: the requested element
"""
self.opt.setowner(self.config, settings.get_owner())
self.config._cfgimpl_previous_values[self.opt._name] = list(self)
self.opt.setowner(self.config,
self.config._cfgimpl_context._cfgimpl_settings.get_owner())
self.config._cfgimpl_context._cfgimpl_values.previous_values[self.opt] = list(self)
return super(Multi, self).pop(key)
# ____________________________________________________________
#
@ -260,11 +263,11 @@ class Option(HiddenBaseType, DisabledBaseType):
if not isinstance(owner, owners.Owner):
raise ConfigError("invalid type owner for option: {0}".format(
str(name)))
config._cfgimpl_value_owners[name] = owner
config._cfgimpl_context._cfgimpl_values.owners[self] = owner
def getowner(self, config):
"config *must* be only the **parent** config (not the toplevel config)"
return config._cfgimpl_value_owners[self._name]
return config._cfgimpl_context._cfgimpl_values.owners[self]
def reset(self, config):
"""resets the default value and owner
@ -285,7 +288,8 @@ class Option(HiddenBaseType, DisabledBaseType):
"""
name = self._name
rootconfig = config._cfgimpl_get_toplevel()
if not self.validate(value, settings.validator):
if not self.validate(value,
config._cfgimpl_context._cfgimpl_settings.validator):
raise ConfigError('invalid value %s for option %s' % (value, name))
if self.is_mandatory():
# value shall not be '' for a mandatory option
@ -294,26 +298,28 @@ 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 settings.is_mandatory() and ((self.is_multi() and value == []) or \
if config._cfgimpl_context._cfgimpl_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:
if self not in config._cfgimpl_context._cfgimpl_values:
raise AttributeError('unknown option %s' % (name))
if settings.is_frozen_for_everything():
if config._cfgimpl_context._cfgimpl_settings.is_frozen_for_everything():
raise TypeError("cannot set a value to the option {} if the whole "
"config has been frozen".format(name))
if settings.is_frozen() and self.is_frozen():
if config._cfgimpl_context._cfgimpl_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)
if type(config._cfgimpl_values[name]) == Multi:
config._cfgimpl_previous_values[name] = list(config._cfgimpl_values[name])
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_previous_values[name] = config._cfgimpl_values[name]
config._cfgimpl_values[name] = value
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):
return value
@ -577,7 +583,8 @@ def apply_requires(opt, config, permissive=False):
except PropertiesOptionError, err:
properties = err.proptype
if permissive:
for perm in settings.permissive:
for perm in \
config._cfgimpl_context._cfgimpl_settings.permissive:
if perm in properties:
properties.remove(perm)
if properties != []:

View file

@ -205,6 +205,3 @@ class Setting():
def get_owner(self):
return self.owner
# Setting is actually a singleton
settings = Setting()

View file

@ -25,90 +25,90 @@ from tiramisu.option import (OptionDescription, Option, ChoiceOption, BoolOption
# ____________________________________________________________
# reverse factory
# XXX HAAAAAAAAAAAACK (but possibly a good one)
def reverse_from_paths(data):
"rebuilds a (fake) data structure from an unflatten `make_dict()` result"
# ____________________________________________________________
_build_map = {
bool: BoolOption,
int: IntOption,
float: FloatOption,
str: StrOption,
}
def option_factory(name, value):
"dummy -> Option('dummy')"
if isinstance(value, list):
return _build_map[type(value[0])](name, '', multi=True, default=value)
else:
return _build_map[type(value)](name, '', default=value)
#def reverse_from_paths(data):
# "rebuilds a (fake) data structure from an unflatten `make_dict()` result"
# # ____________________________________________________________
# _build_map = {
# bool: BoolOption,
# int: IntOption,
# float: FloatOption,
# str: StrOption,
# }
# def option_factory(name, value):
# "dummy -> Option('dummy')"
# if isinstance(value, list):
# return _build_map[type(value[0])](name, '', multi=True, default=value)
# else:
# return _build_map[type(value)](name, '', default=value)
def build_options(data):
"config.gc.dummy -> Option('dummy')"
for key, value in data.items():
name = key.split('.')[-1]
yield (key, option_factory(name, value))
# ____________________________________________________________
def parent(pathname):
"config.gc.dummy -> config.gc"
if "." in pathname:
return ".".join(pathname.split('.')[:-1])
# no parent except rootconfig, naturally returns None
# def build_options(data):
# "config.gc.dummy -> Option('dummy')"
# for key, value in data.items():
# name = key.split('.')[-1]
# yield (key, option_factory(name, value))
# # ____________________________________________________________
# def parent(pathname):
# "config.gc.dummy -> config.gc"
# if "." in pathname:
# return ".".join(pathname.split('.')[:-1])
# # no parent except rootconfig, naturally returns None
def subgroups(pathname):
"config.gc.dummy.bool -> [config.gc, config.gc.dummy]"
group = parent(pathname)
parents =[]
while group is not None:
parents.append(group)
group = parent(group)
return parents
# def subgroups(pathname):
# "config.gc.dummy.bool -> [config.gc, config.gc.dummy]"
# group = parent(pathname)
# parents =[]
# while group is not None:
# parents.append(group)
# group = parent(group)
# return parents
def build_option_descriptions(data):
all_groups = []
for key in data.keys():
for group in subgroups(key):
# so group is unique in the list
if group not in all_groups:
all_groups.append(group)
for group in all_groups:
name = group.split('.')[-1]
yield (group, OptionDescription(name, '', []))
# ____________________________________________________________
descr = OptionDescription('tiramisu', 'fake rebuild structure', [])
cfg = Config(descr)
# add descrs in cfg
def compare(a, b):
l1 = a.split(".")
l2 = b.split(".")
if len(l1) < len(l2):
return -1
elif len(l1) > len(l2):
return 1
else:
return 0
grps = list(build_option_descriptions(data))
groups = dict(grps)
grp_paths = [pathname for pathname, opt_descr in grps]
grp_paths.sort(compare)
for grp in grp_paths:
if not "." in grp:
cfg._cfgimpl_descr.add_child(groups[grp])
cfg.cfgimpl_update()
else:
parentdescr = cfg.unwrap_from_path(parent(grp))
parentdescr.add_child(groups[grp])
getattr(cfg, parent(grp)).cfgimpl_update()
# add options in descrs
for pathname, opt in build_options(data):
current_group_name = parent(pathname)
if current_group_name == None:
cfg._cfgimpl_descr.add_child(opt)
cfg.cfgimpl_update()
else:
curr_grp = groups[current_group_name]
curr_grp.add_child(opt)
getattr(cfg, current_group_name).cfgimpl_update()
# def build_option_descriptions(data):
# all_groups = []
# for key in data.keys():
# for group in subgroups(key):
# # so group is unique in the list
# if group not in all_groups:
# all_groups.append(group)
# for group in all_groups:
# name = group.split('.')[-1]
# yield (group, OptionDescription(name, '', []))
# # ____________________________________________________________
# descr = OptionDescription('tiramisu', 'fake rebuild structure', [])
# cfg = Config(descr)
# # add descrs in cfg
# def compare(a, b):
# l1 = a.split(".")
# l2 = b.split(".")
# if len(l1) < len(l2):
# return -1
# elif len(l1) > len(l2):
# return 1
# else:
# return 0
# grps = list(build_option_descriptions(data))
# groups = dict(grps)
# grp_paths = [pathname for pathname, opt_descr in grps]
# grp_paths.sort(compare)
# for grp in grp_paths:
# if not "." in grp:
# cfg._cfgimpl_descr.add_child(groups[grp])
# cfg.cfgimpl_update()
# else:
# parentdescr = cfg.unwrap_from_path(parent(grp))
# parentdescr.add_child(groups[grp])
# getattr(cfg, parent(grp)).cfgimpl_update()
# # add options in descrs
# for pathname, opt in build_options(data):
# current_group_name = parent(pathname)
# if current_group_name == None:
# cfg._cfgimpl_descr.add_child(opt)
# cfg.cfgimpl_update()
# else:
# curr_grp = groups[current_group_name]
# curr_grp.add_child(opt)
# getattr(cfg, current_group_name).cfgimpl_update()
return cfg
# return cfg
# ____________________________________________________________
# extendable type
class extend(type):

38
tiramisu/value.py Normal file
View file

@ -0,0 +1,38 @@
# -*- coding: utf-8 -*-
"takes care of the option's values"
# 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 OptionValues(object):
def __init__(self):
self.owners = {}
"Config's root indeed is in charge of the `Option()`'s values"
self.values = {}
self.previous_values = {}
def __getitem__(self, opt_or_descr):
return self.values[opt_or_descr]
def __setitem__(self, opt_or_descr, value):
self.values[opt_or_descr] = value
def __contains__(self, opt_or_descr):
return opt_or_descr in self.values