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' assert config.gc.name == 'ref'
config.wantframework = True config.wantframework = True
def test_config_values(): #def test_config_values():
"_cfgimpl_values appears to be a simple dict" # "_cfgimpl_values appears to be a simple dict"
descr = make_description() # descr = make_description()
config = Config(descr) # config = Config(descr)
config.bool = False # config.bool = False
config.set(dummy=False) # config.set(dummy=False)
assert config.gc._cfgimpl_values == {'dummy': False, 'float': 2.3, 'name': 'ref'} # assert config.gc._cfgimpl_values == {'dummy': False, 'float': 2.3, 'name': 'ref'}
def test_cfgimpl_get_home_by_path(): def test_cfgimpl_get_home_by_path():
descr = make_description() descr = make_description()

View File

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

View File

@ -79,18 +79,18 @@ def test_force_default_on_freeze():
assert config.dummy1 == False assert config.dummy1 == False
assert config.dummy2 == False assert config.dummy2 == False
def test_override_are_defaults(): #def test_override_are_defaults():
descr = make_description() # descr = make_description()
config = Config(descr) # config = Config(descr)
config.bool = False # config.bool = False
config.gc.dummy = True # config.gc.dummy = True
assert config._cfgimpl_values['gc']._cfgimpl_value_owners['dummy'] == 'user' # assert config._cfgimpl_values['gc']._cfgimpl_values.owners['dummy'] == 'user'
#Options have an available default setting and can give it back # #Options have an available default setting and can give it back
assert config._cfgimpl_descr._children[0]._children[1].getdefault() == False # assert config._cfgimpl_descr._children[0]._children[1].getdefault() == False
# config.override({'gc.dummy':True}) ## config.override({'gc.dummy':True})
#assert config.gc.dummy == True # #assert config.gc.dummy == True
#assert config._cfgimpl_descr._children[0]._children[1].getdefault() == True # #assert config._cfgimpl_descr._children[0]._children[1].getdefault() == True
#assert config._cfgimpl_values['gc']._cfgimpl_value_owners['dummy'] == 'default' # #assert config._cfgimpl_values['gc']._cfgimpl_value_owners['dummy'] == 'default'
def test_overrides_changes_option_value(): def test_overrides_changes_option_value():
"with config.override(), the default is changed and the value is changed" "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 py.test import raises
from tiramisu.config import * from tiramisu.config import *
from tiramisu.option import * from tiramisu.option import *
from tiramisu.setting import settings, owners from tiramisu.setting import owners
def make_description(): def make_description():
gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref') gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')

View File

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

View File

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

View File

@ -4,7 +4,6 @@ from py.test import raises
from tiramisu.config import * from tiramisu.config import *
from tiramisu.option import * from tiramisu.option import *
from tiramisu.setting import settings
def make_description(): def make_description():
gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref') 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) boolop = BoolOption('boolop', 'Test boolean option op', default=True)
descr = OptionDescription('tiramisu', '', [gcdummy, boolop]) descr = OptionDescription('tiramisu', '', [gcdummy, boolop])
cfg = Config(descr) cfg = Config(descr)
settings = cfg.cfgimpl_get_settings()
settings.enable_property('hiddend') #cfgimpl_hide() settings.enable_property('hiddend') #cfgimpl_hide()
assert cfg.dummy == False assert cfg.dummy == False
assert cfg.boolop == True assert cfg.boolop == True

View File

@ -1,7 +1,7 @@
import autopath #import autopath
from py.test import raises #from py.test import raises
from tool import reverse_from_paths #from tool import reverse_from_paths
#def make_description(): #def make_description():
# gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref') # gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
@ -16,7 +16,7 @@ from tool import reverse_from_paths
# wantref_option = BoolOption('wantref', 'Test requires', default=False) # wantref_option = BoolOption('wantref', 'Test requires', default=False)
# wantframework_option = BoolOption('wantframework', 'Test requires', # wantframework_option = BoolOption('wantframework', 'Test requires',
# default=False) # default=False)
# #
# gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption]) # gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
# descr = OptionDescription('tiram', '', [gcgroup, booloption, objspaceoption, # descr = OptionDescription('tiram', '', [gcgroup, booloption, objspaceoption,
# wantref_option, stroption, # wantref_option, stroption,
@ -24,19 +24,19 @@ from tool import reverse_from_paths
# intoption, boolop]) # intoption, boolop])
# return descr # return descr
def test_rebuild(): #def test_rebuild():
# pouvoir faire une comparaison avec equal # # 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]} # 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) # cfg = reverse_from_paths(d)
assert cfg.s1.s2.s3.s4.a == True # assert cfg.s1.s2.s3.s4.a == True
assert cfg.int == 43 # assert cfg.int == 43
assert cfg.s2.b == True # assert cfg.s2.b == True
assert cfg.s3.c == True # assert cfg.s3.c == True
assert cfg.s3.d == [1,2,3] # assert cfg.s3.d == [1,2,3]
# assert config.getpaths() == ['gc.name', 'gc.dummy', 'gc.float', 'bool', # assert config.getpaths() == ['gc.name', 'gc.dummy', 'gc.float', 'bool',
# 'objspace', 'wantref', 'str', 'wantframework', # 'objspace', 'wantref', 'str', 'wantframework',
# 'int', 'boolop'] # 'int', 'boolop']
# assert config.getpaths(include_groups=False) == ['gc.name', 'gc.dummy', 'gc.float', 'bool', 'objspace', 'wantref', 'str', 'wantframework', 'int', 'boolop'] # assert config.getpaths(include_groups=False) == ['gc.name', 'gc.dummy', 'gc.float', 'bool', 'objspace', 'wantref', 'str', 'wantframework', 'int', 'boolop']
# assert config.getpaths(include_groups=True) == ['gc', 'gc.name', 'gc.dummy', 'gc.float', 'bool', 'objspace', 'wantref', 'str', 'wantframework', 'int', 'boolop'] # assert config.getpaths(include_groups=True) == ['gc', 'gc.name', 'gc.dummy', 'gc.float', 'bool', 'objspace', 'wantref', 'str', 'wantframework', 'int', 'boolop']

View File

@ -26,31 +26,50 @@ from tiramisu.error import (PropertiesOptionError, ConfigError, NotFoundError,
MandatoryError, MethodCallError, NoValueReturned) MandatoryError, MethodCallError, NoValueReturned)
from tiramisu.option import (OptionDescription, Option, SymLinkOption, from tiramisu.option import (OptionDescription, Option, SymLinkOption,
Multi, apply_requires) 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): class Config(object):
"main configuration management entry" "main configuration management entry"
_cfgimpl_toplevel = None _cfgimpl_toplevel = None
def __init__(self, descr, parent=None): def __init__(self, descr, parent=None, context=None):
""" Configuration option management master class """ Configuration option management master class
:param descr: describes the configuration schema :param descr: describes the configuration schema
:type descr: an instance of ``option.OptionDescription`` :type descr: an instance of ``option.OptionDescription``
:param parent: is None if the ``Config`` is root parent Config otherwise :param parent: is None if the ``Config`` is root parent Config otherwise
:type parent: ``Config`` :type parent: ``Config``
:param context: the current root config
:type context: `Config`
""" """
self._cfgimpl_descr = descr self._cfgimpl_descr = descr
self._cfgimpl_value_owners = {}
self._cfgimpl_parent = parent self._cfgimpl_parent = parent
"`Config()` indeed is in charge of the `Option()`'s values" if parent == None:
self._cfgimpl_values = {} self._cfgimpl_settings = Setting()
self._cfgimpl_previous_values = {} 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" "warnings are a great idea, let's make up a better use of it"
self._cfgimpl_warnings = [] self._cfgimpl_warnings = []
self._cfgimpl_toplevel = self._cfgimpl_get_toplevel() self._cfgimpl_toplevel = self._cfgimpl_get_toplevel()
self._cfgimpl_build() 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): def _validate_duplicates(self, children):
"""duplicates Option names in the schema """duplicates Option names in the schema
:type children: list of `Option` or `OptionDescription` :type children: list of `Option` or `OptionDescription`
@ -77,34 +96,35 @@ class Config(object):
childdef = Multi(copy(child.getdefault()), config=self, childdef = Multi(copy(child.getdefault()), config=self,
opt=child) opt=child)
max_len_child = max(max_len_child, len(childdef)) max_len_child = max(max_len_child, len(childdef))
self._cfgimpl_values[child._name] = childdef self._cfgimpl_context._cfgimpl_values[child] = childdef
self._cfgimpl_previous_values[child._name] = list(childdef) self._cfgimpl_context._cfgimpl_values.previous_values[child] = list(childdef)
else: else:
childdef = child.getdefault() childdef = child.getdefault()
self._cfgimpl_values[child._name] = childdef self._cfgimpl_context._cfgimpl_values[child] = childdef
self._cfgimpl_previous_values[child._name] = childdef self._cfgimpl_context._cfgimpl_values.previous_values[child] = childdef
child.setowner(self, owners.default) child.setowner(self, owners.default)
elif isinstance(child, OptionDescription): elif isinstance(child, OptionDescription):
self._validate_duplicates(child._children) 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): # def cfgimpl_update(self):
"""dynamically adds `Option()` or `OptionDescription()` # """dynamically adds `Option()` or `OptionDescription()`
""" # """
# FIXME this is an update for new options in the schema only # # FIXME this is an update for new options in the schema only
# see the update_child() method of the descr object # # see the update_child() method of the descr object
for child in self._cfgimpl_descr._children: # for child in self._cfgimpl_descr._children:
if isinstance(child, Option): # if isinstance(child, Option):
if child._name not in self._cfgimpl_values: # if child._name not in self._cfgimpl_values:
if child.is_multi(): # if child.is_multi():
self._cfgimpl_values[child._name] = Multi( # self._cfgimpl_values[child._name] = Multi(
copy(child.getdefault()), config=self, opt=child) # copy(child.getdefault()), config=self, opt=child)
else: # else:
self._cfgimpl_values[child._name] = copy(child.getdefault()) # self._cfgimpl_values[child._name] = copy(child.getdefault())
child.setowner(self, owners.default) # child.setowner(self, owners.default)
elif isinstance(child, OptionDescription): # elif isinstance(child, OptionDescription):
if child._name not in self._cfgimpl_values: # if child._name not in self._cfgimpl_values:
self._cfgimpl_values[child._name] = Config(child, parent=self) # self._cfgimpl_values[child._name] = Config(child, parent=self)
# ____________________________________________________________ # ____________________________________________________________
# attribute methods # attribute methods
@ -118,7 +138,8 @@ class Config(object):
return setattr(homeconfig, name, value) return setattr(homeconfig, name, value)
if type(getattr(self._cfgimpl_descr, name)) != SymLinkOption: if type(getattr(self._cfgimpl_descr, name)) != SymLinkOption:
self._validate(name, getattr(self._cfgimpl_descr, name)) 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): def _validate(self, name, opt_or_descr, permissive=False):
"validation for the setattr and the getattr" "validation for the setattr and the getattr"
@ -128,10 +149,10 @@ class Config(object):
raise TypeError('Unexpected object: {0}'.format(repr(opt_or_descr))) raise TypeError('Unexpected object: {0}'.format(repr(opt_or_descr)))
properties = copy(opt_or_descr.properties) properties = copy(opt_or_descr.properties)
for proper in copy(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) properties.remove(proper)
if permissive: if permissive:
for perm in settings.permissive: for perm in self._cfgimpl_context._cfgimpl_settings.permissive:
if perm in properties: if perm in properties:
properties.remove(perm) properties.remove(perm)
if properties != []: if properties != []:
@ -142,15 +163,15 @@ class Config(object):
def _is_empty(self, opt): def _is_empty(self, opt):
"convenience method to know if an option is empty" "convenience method to know if an option is empty"
if (not opt.is_multi() and self._cfgimpl_values[opt._name] == None) or \ if (not opt.is_multi() and self._cfgimpl_context._cfgimpl_values[opt] == None) or \
(opt.is_multi() and (self._cfgimpl_values[opt._name] == [] or \ (opt.is_multi() and (self._cfgimpl_context._cfgimpl_values[opt] == [] or \
None in self._cfgimpl_values[opt._name])): None in self._cfgimpl_context._cfgimpl_values[opt])):
return True return True
return False return False
def _test_mandatory(self, path, opt): def _test_mandatory(self, path, opt):
# mandatory options # mandatory options
mandatory = settings.mandatory mandatory = self._cfgimpl_context._cfgimpl_settings.mandatory
if opt.is_mandatory() and mandatory: if opt.is_mandatory() and mandatory:
if self._is_empty(opt) and \ if self._is_empty(opt) and \
opt.is_empty_by_default(): opt.is_empty_by_default():
@ -160,10 +181,11 @@ class Config(object):
def __getattr__(self, name): def __getattr__(self, name):
return self._getattr(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 """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): if not isinstance(result, list):
_result = [result] _result = [result]
else: else:
@ -175,7 +197,7 @@ class Config(object):
attribute notation mechanism for accessing the value of an option attribute notation mechanism for accessing the value of an option
:param name: attribute name :param name: attribute name
:param permissive: permissive doesn't raise some property error :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 :return: option's value if name is an option name, OptionDescription
otherwise otherwise
""" """
@ -189,7 +211,7 @@ class Config(object):
if type(opt_or_descr) == SymLinkOption: if type(opt_or_descr) == SymLinkOption:
rootconfig = self._cfgimpl_get_toplevel() rootconfig = self._cfgimpl_get_toplevel()
return getattr(rootconfig, opt_or_descr.path) 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" % raise AttributeError("%s object has no attribute %s" %
(self.__class__, name)) (self.__class__, name))
self._validate(name, opt_or_descr, permissive) self._validate(name, opt_or_descr, permissive)
@ -202,7 +224,7 @@ class Config(object):
if not isinstance(opt_or_descr, OptionDescription): if not isinstance(opt_or_descr, OptionDescription):
# options with callbacks # options with callbacks
if opt_or_descr.has_callback(): 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 \ if (not opt_or_descr.is_frozen() or \
not opt_or_descr.is_forced_on_freeze()) and \ not opt_or_descr.is_forced_on_freeze()) and \
not opt_or_descr.is_default_owner(self): not opt_or_descr.is_default_owner(self):
@ -214,7 +236,7 @@ class Config(object):
pass pass
else: else:
if opt_or_descr.is_multi(): if opt_or_descr.is_multi():
_result = self.fill_multi(name, result) _result = self.fill_multi(opt_or_descr, result)
else: else:
# this result **shall not** be a list # this result **shall not** be a list
if isinstance(result, list): if isinstance(result, list):
@ -222,22 +244,22 @@ class Config(object):
' for option {0} : shall not be a list'.format(name)) ' for option {0} : shall not be a list'.format(name))
_result = result _result = result
if _result != None and not opt_or_descr.validate(_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' raise ConfigError('invalid calculated value returned'
' for option {0}'.format(name)) ' 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) opt_or_descr.setowner(self, owners.default)
# frozen and force default # frozen and force default
if not opt_or_descr.has_callback() and opt_or_descr.is_forced_on_freeze(): if not opt_or_descr.has_callback() and opt_or_descr.is_forced_on_freeze():
value = opt_or_descr.getdefault() value = opt_or_descr.getdefault()
if opt_or_descr.is_multi(): if opt_or_descr.is_multi():
value = self.fill_multi(name, value, value = self.fill_multi(opt_or_descr, value,
use_default_multi=True, use_default_multi=True,
default_multi=opt_or_descr.getdefault_multi()) 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) opt_or_descr.setowner(self, owners.default)
self._test_mandatory(name, opt_or_descr) self._test_mandatory(name, opt_or_descr)
value = self._cfgimpl_values[name] value = self._cfgimpl_context._cfgimpl_values[opt_or_descr]
return value return value
def unwrap_from_name(self, name): def unwrap_from_name(self, name):
@ -274,7 +296,7 @@ class Config(object):
child = getattr(self._cfgimpl_descr, name) child = getattr(self._cfgimpl_descr, name)
if type(child) != SymLinkOption: if type(child) != SymLinkOption:
if who == None: if who == None:
who = settings.owner who = self._cfgimpl_context._cfgimpl_settings.owner
if child.is_multi(): if child.is_multi():
if not isinstance(who, owners.DefaultOwner): if not isinstance(who, owners.DefaultOwner):
if type(value) != Multi: if type(value) != Multi:
@ -284,7 +306,7 @@ class Config(object):
raise ConfigError("invalid value for option:" raise ConfigError("invalid value for option:"
" {0} that is set to multi".format(name)) " {0} that is set to multi".format(name))
else: else:
value = self.fill_multi(name, child.getdefault(), value = self.fill_multi(child, child.getdefault(),
use_default_multi=True, use_default_multi=True,
default_multi=child.getdefault_multi()) default_multi=child.getdefault_multi())
if not isinstance(who, owners.Owner): if not isinstance(who, owners.Owner):
@ -316,7 +338,8 @@ class Config(object):
pass pass
except Exception, e: except Exception, e:
raise e # HiddenOptionError or DisabledOptionError 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: elif len(candidates) > 1:
raise AmbigousOptionError( raise AmbigousOptionError(
'more than one option that ends with %s' % (key, )) 'more than one option that ends with %s' % (key, ))
@ -371,14 +394,15 @@ class Config(object):
obj = obj._cfgimpl_parent obj = obj._cfgimpl_parent
return ".".join(subpath) return ".".join(subpath)
# ______________________________________________________________________ # ______________________________________________________________________
def cfgimpl_previous_value(self, path): # def cfgimpl_previous_value(self, path):
"stores the previous value" # "stores the previous value"
home, name = self._cfgimpl_get_home_by_path(path) # home, name = self._cfgimpl_get_home_by_path(path)
return home._cfgimpl_previous_values[name] # # FIXME fucking name
# return home._cfgimpl_context._cfgimpl_values.previous_values[name]
def get_previous_value(self, name): # def get_previous_value(self, name):
"for the time being, only the previous Option's value is accessible" # "for the time being, only the previous Option's value is accessible"
return self._cfgimpl_previous_values[name] # return self._cfgimpl_context._cfgimpl_values.previous_values[name]
# ______________________________________________________________________ # ______________________________________________________________________
def add_warning(self, warning): def add_warning(self, warning):
"Config implements its own warning pile. Could be useful" "Config implements its own warning pile. Could be useful"
@ -420,7 +444,7 @@ class Config(object):
can be filtered by categories (families, or whatever). can be filtered by categories (families, or whatever).
:param group_type: if defined, is an instance of `groups.GroupType` :param group_type: if defined, is an instance of `groups.GroupType`
or `groups.MasterGroupType` that lives in or `groups.MasterGroupType` that lives in
`settings.groups` `setting.groups`
""" """
if group_type is not None: if group_type is not None:
@ -592,9 +616,10 @@ def mandatory_warnings(config):
where no value has been set where no value has been set
:returns: generator of mandatory Option's path :returns: generator of mandatory Option's path
FIXME : CAREFULL : not multi-user
""" """
mandatory = settings.mandatory mandatory = config._cfgimpl_context._cfgimpl_settings.mandatory
settings.mandatory = True config._cfgimpl_context._cfgimpl_settings.mandatory = True
for path in config._cfgimpl_descr.getpaths(include_groups=True): for path in config._cfgimpl_descr.getpaths(include_groups=True):
try: try:
value = config._getattr(path, permissive=True) value = config._getattr(path, permissive=True)
@ -602,4 +627,4 @@ def mandatory_warnings(config):
yield path yield path
except PropertiesOptionError: except PropertiesOptionError:
pass 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, RequiresError, RequirementRecursionError, MandatoryError,
PropertiesOptionError) PropertiesOptionError)
from tiramisu.autolib import carry_out_calculation 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')] requires_actions = [('hide', 'show'), ('enable', 'disable'), ('freeze', 'unfreeze')]
@ -53,13 +53,15 @@ class Multi(list):
super(Multi, self).__init__(lst) super(Multi, self).__init__(lst)
def __setitem__(self, key, value): 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): def append(self, value):
"""the list value can be updated (appened) """the list value can be updated (appened)
only if the option is a master 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): def _setvalue(self, value, key=None, who=None):
if value != None: if value != None:
@ -76,7 +78,7 @@ class Multi(list):
raise TypeError("invalid owner {0} for the value {1}".format( raise TypeError("invalid owner {0} for the value {1}".format(
str(who), str(value))) str(who), str(value)))
self.opt.setowner(self.config, getattr(owners, who)) 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): def pop(self, key):
"""the list value can be updated (poped) """the list value can be updated (poped)
@ -86,8 +88,9 @@ class Multi(list):
:return: the requested element :return: the requested element
""" """
self.opt.setowner(self.config, settings.get_owner()) self.opt.setowner(self.config,
self.config._cfgimpl_previous_values[self.opt._name] = list(self) 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) return super(Multi, self).pop(key)
# ____________________________________________________________ # ____________________________________________________________
# #
@ -260,11 +263,11 @@ class Option(HiddenBaseType, DisabledBaseType):
if not isinstance(owner, owners.Owner): if not isinstance(owner, owners.Owner):
raise ConfigError("invalid type owner for option: {0}".format( raise ConfigError("invalid type owner for option: {0}".format(
str(name))) str(name)))
config._cfgimpl_value_owners[name] = owner config._cfgimpl_context._cfgimpl_values.owners[self] = owner
def getowner(self, config): def getowner(self, config):
"config *must* be only the **parent** config (not the toplevel 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): def reset(self, config):
"""resets the default value and owner """resets the default value and owner
@ -285,7 +288,8 @@ class Option(HiddenBaseType, DisabledBaseType):
""" """
name = self._name name = self._name
rootconfig = config._cfgimpl_get_toplevel() 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)) raise ConfigError('invalid value %s for option %s' % (value, name))
if self.is_mandatory(): if self.is_mandatory():
# value shall not be '' for a mandatory option # value shall not be '' for a mandatory option
@ -294,26 +298,28 @@ class Option(HiddenBaseType, DisabledBaseType):
value = None value = None
if self.is_multi() and '' in value: if self.is_multi() and '' in value:
value = Multi([{'': None}.get(i, i) for i in value], config, self) 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)): (not self.is_multi() and value is None)):
raise MandatoryError('cannot change the value to %s for ' raise MandatoryError('cannot change the value to %s for '
'option %s' % (value, name)) '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)) 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 " raise TypeError("cannot set a value to the option {} if the whole "
"config has been frozen".format(name)) "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 ' raise TypeError('cannot change the value to %s for '
'option %s this option is frozen' % (str(value), name)) 'option %s this option is frozen' % (str(value), name))
apply_requires(self, config) apply_requires(self, config)
if type(config._cfgimpl_values[name]) == Multi: if type(config._cfgimpl_context._cfgimpl_values[self]) == Multi:
config._cfgimpl_previous_values[name] = list(config._cfgimpl_values[name]) config._cfgimpl_context._cfgimpl_values.previous_values[self] = list(config._cfgimpl_context._cfgimpl_values[self])
else: else:
config._cfgimpl_previous_values[name] = config._cfgimpl_values[name] config._cfgimpl_context._cfgimpl_values.previous_values[self] = config._cfgimpl_context._cfgimpl_values[self]
config._cfgimpl_values[name] = value config._cfgimpl_context._cfgimpl_values[self] = value
def getkey(self, value): def getkey(self, value):
return value return value
@ -577,7 +583,8 @@ def apply_requires(opt, config, permissive=False):
except PropertiesOptionError, err: except PropertiesOptionError, err:
properties = err.proptype properties = err.proptype
if permissive: if permissive:
for perm in settings.permissive: for perm in \
config._cfgimpl_context._cfgimpl_settings.permissive:
if perm in properties: if perm in properties:
properties.remove(perm) properties.remove(perm)
if properties != []: if properties != []:

View File

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