values are in value objects now
This commit is contained in:
parent
29914051e0
commit
9259a6e3f7
13 changed files with 303 additions and 234 deletions
|
@ -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()
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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():
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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')
|
||||
|
@ -16,7 +16,7 @@ from tool import reverse_from_paths
|
|||
# wantref_option = BoolOption('wantref', 'Test requires', default=False)
|
||||
# wantframework_option = BoolOption('wantframework', 'Test requires',
|
||||
# default=False)
|
||||
#
|
||||
#
|
||||
# gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
|
||||
# descr = OptionDescription('tiram', '', [gcgroup, booloption, objspaceoption,
|
||||
# wantref_option, stroption,
|
||||
|
@ -24,19 +24,19 @@ 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',
|
||||
# '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']
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 != []:
|
||||
|
|
|
@ -205,6 +205,3 @@ class Setting():
|
|||
|
||||
def get_owner(self):
|
||||
return self.owner
|
||||
|
||||
# Setting is actually a singleton
|
||||
settings = Setting()
|
||||
|
|
160
tiramisu/tool.py
160
tiramisu/tool.py
|
@ -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
38
tiramisu/value.py
Normal 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
|
Loading…
Reference in a new issue