* config herite from BaseInformation class

* _cfgimpl_ => _impl_
* optimpl_ => impl_
* properties/permissives are now set/frozenset
* validation raise ValueError if not valid, didn't return anything otherwise
* consistencies are now validate in setting and when deleting value
* ip/network with netmask consistency now works
* DomainnameOption now works
* if no validation, don't set cache for value
* symlinkoption: remove path (not used)
This commit is contained in:
Emmanuel Garette 2013-05-08 18:14:42 +02:00
parent 1b29793e0f
commit 6de65859b4
16 changed files with 781 additions and 571 deletions

View File

@ -104,3 +104,11 @@ def test_cfgimpl_get_home_by_path():
assert config.cfgimpl_get_home_by_path('dummy')[1] == 'dummy' assert config.cfgimpl_get_home_by_path('dummy')[1] == 'dummy'
#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']
def test_information_config():
descr = make_description()
config = Config(descr)
string = 'some informations'
config.impl_set_information('info', string)
assert config.impl_get_information('info') == string

View File

@ -0,0 +1,37 @@
import autopath
from py.test import raises
from tiramisu.config import Config
from tiramisu.option import DomainnameOption, OptionDescription
def test_domainname():
d = DomainnameOption('d', '')
od = OptionDescription('a', '', [d])
c = Config(od)
c.d = 'toto.com'
raises(ValueError, "c.d = 'toto'")
c.d = 'toto3.com'
c.d = 'toto3.3la'
raises(ValueError, "c.d = '3toto.com'")
c.d = 'toto.co3'
raises(ValueError, "c.d = 'toto_super.com'")
c.d = 'toto-.com'
def test_domainname_netbios():
d = DomainnameOption('d', '', type_='netbios')
od = OptionDescription('a', '', [d])
c = Config(od)
raises(ValueError, "c.d = 'toto.com'")
c.d = 'toto'
raises(ValueError, "c.d = 'domainnametoolong'")
def test_domainname_hostname():
d = DomainnameOption('d', '', type_='hostname')
od = OptionDescription('a', '', [d])
c = Config(od)
raises(ValueError, "c.d = 'toto.com'")
c.d = 'toto'
c.d = 'domainnametoolong'

45
test/test_config_ip.py Normal file
View File

@ -0,0 +1,45 @@
import autopath
from py.test import raises
from tiramisu.setting import owners
from tiramisu.config import Config
from tiramisu.option import IPOption, NetworkOption, NetmaskOption, \
OptionDescription
def test_ip():
a = IPOption('a', '')
b = IPOption('b', '', only_private=True)
od = OptionDescription('od', '', [a, b])
c = Config(od)
c.a = '192.168.1.1'
c.a = '192.168.1.0'
c.a = '88.88.88.88'
c.a = '0.0.0.0'
assert(ValueError, "c.a = '255.255.255.0'")
c.b = '192.168.1.1'
c.b = '192.168.1.0'
assert(ValueError, "c.b = '88.88.88.88'")
c.b = '0.0.0.0'
assert(ValueError, "c.b = '255.255.255.0'")
def test_network():
a = NetworkOption('a', '')
od = OptionDescription('od', '', [a])
c = Config(od)
c.a = '192.168.1.1'
c.a = '192.168.1.0'
c.a = '88.88.88.88'
c.a = '0.0.0.0'
assert(ValueError, "c.a = '255.255.255.0'")
def test_netmask():
a = NetmaskOption('a', '')
od = OptionDescription('od', '', [a])
c = Config(od)
assert(ValueError, "c.a = '192.168.1.1'")
assert(ValueError, "c.a = '192.168.1.0'")
assert(ValueError, "c.a = '88.88.88.88'")
c.a = '0.0.0.0'
c.a = '255.255.255.0'

View File

@ -29,7 +29,7 @@ def make_description():
#FIXME ne pas mettre 2 OD differents dans un meta #FIXME ne pas mettre 2 OD differents dans un meta
def test_none(): def test_none():
meta = make_description() meta = make_description()
conf1, conf2 = meta._cfgimpl_children conf1, conf2 = meta._impl_children
assert conf1.od1.i3 is conf2.od1.i3 is None assert conf1.od1.i3 is conf2.od1.i3 is None
assert conf1.getowner('od1.i3') is conf2.getowner('od1.i3') is owners.default assert conf1.getowner('od1.i3') is conf2.getowner('od1.i3') is owners.default
meta.od1.i3 = 3 meta.od1.i3 = 3
@ -58,7 +58,7 @@ def test_none():
def test_default(): def test_default():
meta = make_description() meta = make_description()
conf1, conf2 = meta._cfgimpl_children conf1, conf2 = meta._impl_children
assert conf1.od1.i2 == conf2.od1.i2 == 1 assert conf1.od1.i2 == conf2.od1.i2 == 1
assert conf1.getowner('od1.i2') is conf2.getowner('od1.i2') is owners.default assert conf1.getowner('od1.i2') is conf2.getowner('od1.i2') is owners.default
meta.od1.i2 = 3 meta.od1.i2 = 3
@ -87,7 +87,7 @@ def test_default():
def test_contexts(): def test_contexts():
meta = make_description() meta = make_description()
conf1, conf2 = meta._cfgimpl_children conf1, conf2 = meta._impl_children
assert conf1.od1.i2 == conf2.od1.i2 == 1 assert conf1.od1.i2 == conf2.od1.i2 == 1
assert conf1.getowner('od1.i2') is conf2.getowner('od1.i2') is owners.default assert conf1.getowner('od1.i2') is conf2.getowner('od1.i2') is owners.default
meta.set_contexts('od1.i2', 6) meta.set_contexts('od1.i2', 6)
@ -108,7 +108,7 @@ def test_meta_meta():
meta1 = make_description() meta1 = make_description()
meta2 = MetaConfig([meta1]) meta2 = MetaConfig([meta1])
meta2.cfgimpl_get_settings().setowner(owners.meta) meta2.cfgimpl_get_settings().setowner(owners.meta)
conf1, conf2 = meta1._cfgimpl_children conf1, conf2 = meta1._impl_children
assert conf1.od1.i2 == conf2.od1.i2 == 1 assert conf1.od1.i2 == conf2.od1.i2 == 1
assert conf1.getowner('od1.i2') is conf2.getowner('od1.i2') is owners.default assert conf1.getowner('od1.i2') is conf2.getowner('od1.i2') is owners.default
meta2.od1.i2 = 3 meta2.od1.i2 = 3
@ -142,7 +142,7 @@ def test_meta_meta_set():
meta1 = make_description() meta1 = make_description()
meta2 = MetaConfig([meta1]) meta2 = MetaConfig([meta1])
meta2.cfgimpl_get_settings().setowner(owners.meta) meta2.cfgimpl_get_settings().setowner(owners.meta)
conf1, conf2 = meta1._cfgimpl_children conf1, conf2 = meta1._impl_children
meta2.set_contexts('od1.i1', 7) meta2.set_contexts('od1.i1', 7)
assert conf1.od1.i1 == conf2.od1.i1 == 7 assert conf1.od1.i1 == conf2.od1.i1 == 7
assert conf1.getowner('od1.i1') is conf2.getowner('od1.i1') is owners.user assert conf1.getowner('od1.i1') is conf2.getowner('od1.i1') is owners.user
@ -160,7 +160,7 @@ def test_not_meta():
conf2 = Config(od2) conf2 = Config(od2)
meta = MetaConfig([conf1, conf2], False) meta = MetaConfig([conf1, conf2], False)
raises(ConfigError, 'meta.od1.i1') raises(ConfigError, 'meta.od1.i1')
conf1, conf2 = meta._cfgimpl_children conf1, conf2 = meta._impl_children
meta.set_contexts('od1.i1', 7) meta.set_contexts('od1.i1', 7)
assert conf1.od1.i1 == conf2.od1.i1 == 7 assert conf1.od1.i1 == conf2.od1.i1 == 7
assert conf1.getowner('od1.i1') is conf2.getowner('od1.i1') is owners.user assert conf1.getowner('od1.i1') is conf2.getowner('od1.i1') is owners.user

View File

@ -0,0 +1,271 @@
import autopath
from py.test import raises
from tiramisu.config import Config
from tiramisu.option import ChoiceOption, BoolOption, IntOption, FloatOption, \
StrOption, IPOption, OptionDescription
from tiramisu.error import PropertiesOptionError, ConflictError
def make_description():
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
gcdummy = BoolOption('dummy', 'dummy', default=False)
objspaceoption = ChoiceOption('objspace', 'Object space',
('std', 'thunk'), 'std')
booloption = BoolOption('bool', 'Test boolean option', default=True)
intoption = IntOption('int', 'Test int option', default=0)
intoption2 = IntOption('int', 'Test int option', default=0)
floatoption = FloatOption('float', 'Test float option', default=2.3)
stroption = StrOption('str', 'Test string option', default="abc")
boolop = BoolOption('boolop', 'Test boolean option op', default=True)
wantref_option = BoolOption('wantref', 'Test requires', default=False,
requires=((boolop, True, 'hidden'),))
wantframework_option = BoolOption('wantframework', 'Test requires',
default=False,
requires=((boolop, True, 'hidden'),))
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption, intoption2])
descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
wantref_option, stroption,
wantframework_option,
intoption, boolop])
return descr
def make_description_duplicates():
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
## dummy 1
gcdummy = BoolOption('dummy', 'dummy', default=False)
objspaceoption = ChoiceOption('objspace', 'Object space',
('std', 'thunk'), 'std')
booloption = BoolOption('bool', 'Test boolean option', default=True)
intoption = IntOption('int', 'Test int option', default=0)
floatoption = FloatOption('float', 'Test float option', default=2.3)
stroption = StrOption('str', 'Test string option', default="abc")
boolop = BoolOption('boolop', 'Test boolean option op', default=True)
wantref_option = BoolOption('wantref', 'Test requires', default=False,
requires=((boolop, True, 'hidden'),))
wantframework_option = BoolOption('wantframework', 'Test requires',
default=False,
requires=((boolop, True, 'hidden'),))
# dummy2 (same path)
gcdummy2 = BoolOption('dummy', 'dummy2', default=True)
# dummy3 (same name)
gcdummy3 = BoolOption('dummy', 'dummy2', default=True)
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, gcdummy2, floatoption])
descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
wantref_option, stroption,
wantframework_option,
intoption, boolop, gcdummy3])
return descr
def test_identical_paths():
"""If in the schema (the option description) there is something that
have the same name, an exection is raised
"""
raises(ConflictError, "make_description_duplicates()")
def make_description2():
gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref')
gcdummy = BoolOption('dummy', 'dummy', default=False)
floatoption = FloatOption('float', 'Test float option', default=2.3)
objspaceoption = ChoiceOption('objspace', 'Object space',
['std', 'thunk'], 'std')
booloption = BoolOption('bool', 'Test boolean option', default=True)
intoption = IntOption('int', 'Test int option', default=0)
stroption = StrOption('str', 'Test string option', default="abc")
# first multi
boolop = BoolOption('boolop', 'Test boolean option op', default=True)
boolop.enable_multi()
wantref_option = BoolOption('wantref', 'Test requires', default=False,
requires=((boolop, True, 'hidden'),))
# second multi
wantframework_option = BoolOption('wantframework', 'Test requires',
default=False,
requires=((boolop, True, 'hidden'),))
wantframework_option.enable_multi()
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
wantref_option, stroption,
wantframework_option,
intoption, boolop])
return descr
# FIXME: il faudra tester les validations sur les multis
#def test_multi_constraints():
# "a multi in a constraint has to have the same length"
# descr = make_description2()
# cfg = Config(descr)
# cfg.boolop = [True, True, False]
# cfg.wantframework = [False, False, True]
#
#def test_multi_raise():
# "a multi in a constraint has to have the same length"
# # FIXME fusionner les deux tests, MAIS PROBLEME :
# # il ne devrait pas etre necessaire de refaire une config
# # si la valeur est modifiee une deuxieme fois ->
# #raises(ConflictConfigError, "cfg.wantframework = [False, False, True]")
# # ExceptionFailure: 'DID NOT RAISE'
# descr = make_description2()
# cfg = Config(descr)
# cfg.boolop = [True]
# raises(ConflictConfigError, "cfg.wantframework = [False, False, True]")
# ____________________________________________________________
# adding dynamically new options description schema
#def test_newoption_add_in_descr():
# descr = make_description()
# newoption = BoolOption('newoption', 'dummy twoo', default=False)
# descr.add_child(newoption)
# config = Config(descr)
# assert config.newoption == False
#def test_newoption_add_in_subdescr():
# descr = make_description()
# newoption = BoolOption('newoption', 'dummy twoo', default=False)
# descr.gc.add_child(newoption)
# config = Config(descr)
# 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 make_description_requires():
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
gcdummy = BoolOption('dummy', 'dummy', default=False)
floatoption = FloatOption('float', 'Test float option', default=2.3)
objspaceoption = ChoiceOption('objspace', 'Object space',
('std', 'thunk'), 'std')
booloption = BoolOption('bool', 'Test boolean option', default=True)
intoption = IntOption('int', 'Test int option', default=0)
stroption = StrOption('str', 'Test string option', default="abc",
requires=((intoption, 1, 'hidden'),))
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
stroption, intoption])
return descr
def test_hidden_if_in():
descr = make_description_requires()
cfg = Config(descr)
setting = cfg.cfgimpl_get_settings()
cfg.read_write()
stroption = cfg.unwrap_from_path('str')
assert not 'hidden' in setting[stroption]
cfg.int = 1
raises(PropertiesOptionError, "cfg.str")
raises(PropertiesOptionError, 'cfg.str="uvw"')
assert 'hidden' in setting[stroption]
def test_hidden_if_in_with_group():
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
gcdummy = BoolOption('dummy', 'dummy', default=False)
floatoption = FloatOption('float', 'Test float option', default=2.3)
objspaceoption = ChoiceOption('objspace', 'Object space',
('std', 'thunk'), 'std')
booloption = BoolOption('bool', 'Test boolean option', default=True)
intoption = IntOption('int', 'Test int option', default=0)
stroption = StrOption('str', 'Test string option', default="abc")
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption],
requires=((intoption, 1, 'hidden'),))
descr = OptionDescription('constraints', '', [gcgroup, booloption,
objspaceoption, stroption, intoption])
cfg = Config(descr)
setting = cfg.cfgimpl_get_settings()
cfg.read_write()
assert not 'hidden' in setting[stroption]
cfg.int = 1
raises(PropertiesOptionError, "cfg.gc.name")
def test_disabled_with_group():
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
gcdummy = BoolOption('dummy', 'dummy', default=False)
floatoption = FloatOption('float', 'Test float option', default=2.3)
objspaceoption = ChoiceOption('objspace', 'Object space',
('std', 'thunk'), 'std')
booloption = BoolOption('bool', 'Test boolean option', default=True)
intoption = IntOption('int', 'Test int option', default=0)
stroption = StrOption('str', 'Test string option', default="abc")
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption],
requires=((intoption, 1, 'disabled'),))
descr = OptionDescription('constraints', '', [gcgroup, booloption,
objspaceoption, stroption, intoption])
cfg = Config(descr)
cfg.read_write()
assert cfg.gc.name
cfg.int = 1
raises(PropertiesOptionError, "cfg.gc.name")
#____________________________________________________________
def make_description_callback():
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
gcdummy = BoolOption('dummy', 'dummy')
objspaceoption = ChoiceOption('objspace', 'Object space',
('std', 'thunk'), 'std')
booloption = BoolOption('bool', 'Test boolean option', default=True)
intoption = IntOption('int', 'Test int option', default=0)
floatoption = FloatOption('float', 'Test float option', default=2.3)
stroption = StrOption('str', 'Test string option', default="abc")
boolop = BoolOption('boolop', 'Test boolean option op', default=True)
wantref_option = BoolOption('wantref', 'Test requires', default=False,
requires=((boolop, True, 'hidden'),))
wantframework_option = BoolOption('wantframework', 'Test requires',
default=False,
requires=((boolop, True, 'hidden'),))
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
wantref_option, stroption,
wantframework_option,
intoption, boolop])
return descr
def test_has_callback():
descr = make_description_callback()
# here the owner is 'default'
config = Config(descr)
setting = config.cfgimpl_get_settings()
config.read_write()
config.bool = False
# because dummy has a callback
dummy = config.unwrap_from_path('gc.dummy')
setting.append('freeze')
setting[dummy].append('frozen')
raises(PropertiesOptionError, "config.gc.dummy = True")
def test_freeze_and_has_callback():
descr = make_description_callback()
config = Config(descr)
setting = config.cfgimpl_get_settings()
config.read_write()
config.bool = False
setting = config.cfgimpl_get_settings()
setting.append('freeze')
dummy = config.unwrap_from_path('gc.dummy')
setting[dummy].append('frozen')
raises(PropertiesOptionError, "config.gc.dummy = True")

View File

@ -1,270 +1,70 @@
import autopath import autopath
from py.test import raises from py.test import raises
from tiramisu.setting import owners
from tiramisu.config import Config from tiramisu.config import Config
from tiramisu.option import ChoiceOption, BoolOption, IntOption, FloatOption, \ from tiramisu.option import IPOption, NetworkOption, NetmaskOption, IntOption,\
StrOption, OptionDescription OptionDescription
from tiramisu.error import PropertiesOptionError, ConflictError
def make_description(): def test_consistency_not_equal():
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref') a = IntOption('a', '')
gcdummy = BoolOption('dummy', 'dummy', default=False) b = IntOption('b', '')
objspaceoption = ChoiceOption('objspace', 'Object space', od = OptionDescription('od', '', [a, b])
('std', 'thunk'), 'std') a.impl_add_consistency('not_equal', (a, b))
booloption = BoolOption('bool', 'Test boolean option', default=True) c = Config(od)
intoption = IntOption('int', 'Test int option', default=0) assert c.a is None
floatoption = FloatOption('float', 'Test float option', default=2.3) assert c.b is None
stroption = StrOption('str', 'Test string option', default="abc") c.a = 1
boolop = BoolOption('boolop', 'Test boolean option op', default=True) del(c.a)
wantref_option = BoolOption('wantref', 'Test requires', default=False, c.a = 1
requires=((boolop, True, 'hidden'),)) raises(ValueError, "c.b = 1")
wantframework_option = BoolOption('wantframework', 'Test requires', c.b = 2
default=False,
requires=((boolop, True, 'hidden'),))
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
wantref_option, stroption,
wantframework_option,
intoption, boolop])
return descr
def make_description_duplicates(): def test_consistency_default():
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref') a = IntOption('a', '', 1)
## dummy 1 b = IntOption('b', '', 1)
gcdummy = BoolOption('dummy', 'dummy', default=False) raises(ValueError, "a.impl_add_consistency('not_equal', (a, b))")
objspaceoption = ChoiceOption('objspace', 'Object space',
('std', 'thunk'), 'std')
booloption = BoolOption('bool', 'Test boolean option', default=True)
intoption = IntOption('int', 'Test int option', default=0)
floatoption = FloatOption('float', 'Test float option', default=2.3)
stroption = StrOption('str', 'Test string option', default="abc")
boolop = BoolOption('boolop', 'Test boolean option op', default=True)
wantref_option = BoolOption('wantref', 'Test requires', default=False,
requires=((boolop, True, 'hidden'),))
wantframework_option = BoolOption('wantframework', 'Test requires',
default=False,
requires=((boolop, True, 'hidden'),))
# dummy2 (same path)
gcdummy2 = BoolOption('dummy', 'dummy2', default=True)
# dummy3 (same name)
gcdummy3 = BoolOption('dummy', 'dummy2', default=True)
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, gcdummy2, floatoption])
descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
wantref_option, stroption,
wantframework_option,
intoption, boolop, gcdummy3])
return descr
def test_identical_paths(): def test_consistency_default_diff():
"""If in the schema (the option description) there is something that a = IntOption('a', '', 3)
have the same name, an exection is raised b = IntOption('b', '', 1)
""" od = OptionDescription('od', '', [a, b])
raises(ConflictError, "make_description_duplicates()") a.impl_add_consistency('not_equal', (a, b))
c = Config(od)
raises(ValueError, "c.a = 1")
c.a = 2
c.b = 3
assert c.getowner('a') is owners.user
raises(ValueError, "del(c.a)")
assert c.getowner('a') is owners.user
def make_description2(): def test_consistency_ip_netmask():
gcoption = ChoiceOption('name', 'GC name', ['ref', 'framework'], 'ref') a = IPOption('a', '')
gcdummy = BoolOption('dummy', 'dummy', default=False) b = NetmaskOption('b', '')
od = OptionDescription('od', '', [a, b])
floatoption = FloatOption('float', 'Test float option', default=2.3) b.impl_add_consistency('ip_netmask', (b, a))
c = Config(od)
objspaceoption = ChoiceOption('objspace', 'Object space', c.a = '192.168.1.1'
['std', 'thunk'], 'std') c.b = '255.255.255.0'
booloption = BoolOption('bool', 'Test boolean option', default=True) c.a = '192.168.1.2'
intoption = IntOption('int', 'Test int option', default=0) c.b = '255.255.255.255'
stroption = StrOption('str', 'Test string option', default="abc") c.b = '255.255.255.0'
# first multi raises(ValueError, "c.a = '192.168.1.0'")
boolop = BoolOption('boolop', 'Test boolean option op', default=True)
boolop.enable_multi()
wantref_option = BoolOption('wantref', 'Test requires', default=False,
requires=((boolop, True, 'hidden'),))
# second multi
wantframework_option = BoolOption('wantframework', 'Test requires',
default=False,
requires=((boolop, True, 'hidden'),))
wantframework_option.enable_multi()
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
wantref_option, stroption,
wantframework_option,
intoption, boolop])
return descr
# FIXME: il faudra tester les validations sur les multis def test_consistency_network_netmask():
#def test_multi_constraints(): a = NetworkOption('a', '')
# "a multi in a constraint has to have the same length" b = NetmaskOption('b', '')
# descr = make_description2() od = OptionDescription('od', '', [a, b])
# cfg = Config(descr) b.impl_add_consistency('network_netmask', (b, a))
# cfg.boolop = [True, True, False] c = Config(od)
# cfg.wantframework = [False, False, True] c.a = '192.168.1.1'
# c.b = '255.255.255.255'
#def test_multi_raise(): del(c.b)
# "a multi in a constraint has to have the same length" c.a = '192.168.1.0'
# # FIXME fusionner les deux tests, MAIS PROBLEME : c.b = '255.255.255.0'
# # il ne devrait pas etre necessaire de refaire une config raises(ValueError, "c.a = '192.168.1.1'")
# # si la valeur est modifiee une deuxieme fois ->
# #raises(ConflictConfigError, "cfg.wantframework = [False, False, True]")
# # ExceptionFailure: 'DID NOT RAISE'
# descr = make_description2()
# cfg = Config(descr)
# cfg.boolop = [True]
# raises(ConflictConfigError, "cfg.wantframework = [False, False, True]")
# ____________________________________________________________
# adding dynamically new options description schema
#def test_newoption_add_in_descr():
# descr = make_description()
# newoption = BoolOption('newoption', 'dummy twoo', default=False)
# descr.add_child(newoption)
# config = Config(descr)
# assert config.newoption == False
#def test_newoption_add_in_subdescr():
# descr = make_description()
# newoption = BoolOption('newoption', 'dummy twoo', default=False)
# descr.gc.add_child(newoption)
# config = Config(descr)
# 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 make_description_requires():
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
gcdummy = BoolOption('dummy', 'dummy', default=False)
floatoption = FloatOption('float', 'Test float option', default=2.3)
objspaceoption = ChoiceOption('objspace', 'Object space',
('std', 'thunk'), 'std')
booloption = BoolOption('bool', 'Test boolean option', default=True)
intoption = IntOption('int', 'Test int option', default=0)
stroption = StrOption('str', 'Test string option', default="abc",
requires=((intoption, 1, 'hidden'),))
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
stroption, intoption])
return descr
def test_hidden_if_in():
descr = make_description_requires()
cfg = Config(descr)
setting = cfg.cfgimpl_get_settings()
cfg.read_write()
stroption = cfg.unwrap_from_path('str')
assert not 'hidden' in setting[stroption]
cfg.int = 1
raises(PropertiesOptionError, "cfg.str")
raises(PropertiesOptionError, 'cfg.str="uvw"')
assert 'hidden' in setting[stroption]
def test_hidden_if_in_with_group():
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
gcdummy = BoolOption('dummy', 'dummy', default=False)
floatoption = FloatOption('float', 'Test float option', default=2.3)
objspaceoption = ChoiceOption('objspace', 'Object space',
('std', 'thunk'), 'std')
booloption = BoolOption('bool', 'Test boolean option', default=True)
intoption = IntOption('int', 'Test int option', default=0)
stroption = StrOption('str', 'Test string option', default="abc")
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption],
requires=((intoption, 1, 'hidden'),))
descr = OptionDescription('constraints', '', [gcgroup, booloption,
objspaceoption, stroption, intoption])
cfg = Config(descr)
setting = cfg.cfgimpl_get_settings()
cfg.read_write()
assert not 'hidden' in setting[stroption]
cfg.int = 1
raises(PropertiesOptionError, "cfg.gc.name")
def test_disabled_with_group():
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
gcdummy = BoolOption('dummy', 'dummy', default=False)
floatoption = FloatOption('float', 'Test float option', default=2.3)
objspaceoption = ChoiceOption('objspace', 'Object space',
('std', 'thunk'), 'std')
booloption = BoolOption('bool', 'Test boolean option', default=True)
intoption = IntOption('int', 'Test int option', default=0)
stroption = StrOption('str', 'Test string option', default="abc")
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption],
requires=((intoption, 1, 'disabled'),))
descr = OptionDescription('constraints', '', [gcgroup, booloption,
objspaceoption, stroption, intoption])
cfg = Config(descr)
cfg.read_write()
assert cfg.gc.name
cfg.int = 1
raises(PropertiesOptionError, "cfg.gc.name")
#____________________________________________________________
def make_description_callback():
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
gcdummy = BoolOption('dummy', 'dummy')
objspaceoption = ChoiceOption('objspace', 'Object space',
('std', 'thunk'), 'std')
booloption = BoolOption('bool', 'Test boolean option', default=True)
intoption = IntOption('int', 'Test int option', default=0)
floatoption = FloatOption('float', 'Test float option', default=2.3)
stroption = StrOption('str', 'Test string option', default="abc")
boolop = BoolOption('boolop', 'Test boolean option op', default=True)
wantref_option = BoolOption('wantref', 'Test requires', default=False,
requires=((boolop, True, 'hidden'),))
wantframework_option = BoolOption('wantframework', 'Test requires',
default=False,
requires=((boolop, True, 'hidden'),))
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
descr = OptionDescription('constraints', '', [gcgroup, booloption, objspaceoption,
wantref_option, stroption,
wantframework_option,
intoption, boolop])
return descr
def test_has_callback():
descr = make_description_callback()
# here the owner is 'default'
config = Config(descr)
setting = config.cfgimpl_get_settings()
config.read_write()
config.bool = False
# because dummy has a callback
dummy = config.unwrap_from_path('gc.dummy')
setting.append('freeze')
setting[dummy].append('frozen')
raises(PropertiesOptionError, "config.gc.dummy = True")
def test_freeze_and_has_callback():
descr = make_description_callback()
config = Config(descr)
setting = config.cfgimpl_get_settings()
config.read_write()
config.bool = False
setting = config.cfgimpl_get_settings()
setting.append('freeze')
dummy = config.unwrap_from_path('gc.dummy')
setting[dummy].append('frozen')
raises(PropertiesOptionError, "config.gc.dummy = True")

View File

@ -50,7 +50,7 @@ def test_default_is_none():
def test_set_defaut_value_from_option_object(): def test_set_defaut_value_from_option_object():
"""Options have an available default setting and can give it back""" """Options have an available default setting and can give it back"""
b = BoolOption("boolean", "", default=False) b = BoolOption("boolean", "", default=False)
assert b.optimpl_getdefault() is False assert b.impl_getdefault() is False
def test_force_default_on_freeze(): def test_force_default_on_freeze():

View File

@ -233,7 +233,7 @@ def test_multi_with_bool():
s = BoolOption("bool", "", default=[False], multi=True) s = BoolOption("bool", "", default=[False], multi=True)
descr = OptionDescription("options", "", [s]) descr = OptionDescription("options", "", [s])
config = Config(descr) config = Config(descr)
assert descr.bool.optimpl_is_multi() is True assert descr.bool.impl_is_multi() is True
config.bool = [True, False] config.bool = [True, False]
assert config.cfgimpl_get_values()[s] == [True, False] assert config.cfgimpl_get_values()[s] == [True, False]
assert config.bool == [True, False] assert config.bool == [True, False]
@ -243,7 +243,7 @@ def test_multi_with_bool_two():
s = BoolOption("bool", "", default=[False], multi=True) s = BoolOption("bool", "", default=[False], multi=True)
descr = OptionDescription("options", "", [s]) descr = OptionDescription("options", "", [s])
config = Config(descr) config = Config(descr)
assert descr.bool.optimpl_is_multi() is True assert descr.bool.impl_is_multi() is True
raises(ValueError, "config.bool = True") raises(ValueError, "config.bool = True")
@ -258,7 +258,7 @@ def test_choice_access_with_multi():
#____________________________________________________________ #____________________________________________________________
def test_symlink_option(): def test_symlink_option():
boolopt = BoolOption("b", "", default=False) boolopt = BoolOption("b", "", default=False)
linkopt = SymLinkOption("c", "s1.b", opt=boolopt) linkopt = SymLinkOption("c", boolopt)
descr = OptionDescription("opt", "", descr = OptionDescription("opt", "",
[linkopt, OptionDescription("s1", "", [boolopt])]) [linkopt, OptionDescription("s1", "", [boolopt])])
config = Config(descr) config = Config(descr)
@ -280,10 +280,10 @@ def test_accepts_multiple_changes_from_option():
descr = OptionDescription("options", "", [s]) descr = OptionDescription("options", "", [s])
config = Config(descr) config = Config(descr)
config.string = "egg" config.string = "egg"
assert s.optimpl_getdefault() == "string" assert s.impl_getdefault() == "string"
assert config.string == "egg" assert config.string == "egg"
config.string = 'blah' config.string = 'blah'
assert s.optimpl_getdefault() == "string" assert s.impl_getdefault() == "string"
assert config.string == "blah" assert config.string == "blah"
config.string = 'bol' config.string = 'bol'
assert config.string == 'bol' assert config.string == 'bol'

View File

@ -119,5 +119,5 @@ def test_with_many_subgroups():
path = 'gc.subgroup.booltwo' path = 'gc.subgroup.booltwo'
homeconfig, name = config.cfgimpl_get_home_by_path(path) homeconfig, name = config.cfgimpl_get_home_by_path(path)
assert name == "booltwo" assert name == "booltwo"
getattr(homeconfig._cfgimpl_descr, name) getattr(homeconfig.cfgimpl_get_description(), name)
assert 'hidden' in setting[booltwo] assert 'hidden' in setting[booltwo]

View File

@ -50,7 +50,7 @@ def test_optname_shall_not_start_with_numbers():
def test_option_has_an_api_name(): def test_option_has_an_api_name():
raises(ValueError, "BoolOption('cfgimpl_get_settings', 'dummy', default=False)") raises(ValueError, "BoolOption('cfgimpl_get_settings', 'dummy', default=False)")
raises(ValueError, "BoolOption('unwrap_from_path', 'dummy', default=False)") raises(ValueError, "BoolOption('unwrap_from_path', 'dummy', default=False)")
raises(ValueError, "BoolOption('optimpl_getdoc', 'dummy', default=False)") raises(ValueError, "BoolOption('impl_getdoc', 'dummy', default=False)")
raises(ValueError, "BoolOption('_unvalid', 'dummy', default=False)") raises(ValueError, "BoolOption('_unvalid', 'dummy', default=False)")
raises(ValueError, "BoolOption('6unvalid', 'dummy', default=False)") raises(ValueError, "BoolOption('6unvalid', 'dummy', default=False)")
BoolOption('unvalid6', 'dummy', default=False) BoolOption('unvalid6', 'dummy', default=False)

View File

@ -27,13 +27,13 @@ def make_description():
master = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0]) master = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
interface1 = OptionDescription('interface1', '', [master]) interface1 = OptionDescription('interface1', '', [master])
interface1.optimpl_set_group_type(groups.family) interface1.impl_set_group_type(groups.family)
general = OptionDescription('general', '', [numero_etab, nom_machine, general = OptionDescription('general', '', [numero_etab, nom_machine,
nombre_interfaces, activer_proxy_client, nombre_interfaces, activer_proxy_client,
mode_conteneur_actif, adresse_serveur_ntp, mode_conteneur_actif, adresse_serveur_ntp,
time_zone]) time_zone])
general.optimpl_set_group_type(groups.family) general.impl_set_group_type(groups.family)
creole = OptionDescription('creole', 'first tiramisu configuration', [general, interface1]) creole = OptionDescription('creole', 'first tiramisu configuration', [general, interface1])
descr = OptionDescription('baseconfig', 'baseconifgdescr', [creole]) descr = OptionDescription('baseconfig', 'baseconifgdescr', [creole])
return descr return descr
@ -74,10 +74,10 @@ def test_get_group_type():
descr = make_description() descr = make_description()
config = Config(descr) config = Config(descr)
grp = config.unwrap_from_path('creole.general') grp = config.unwrap_from_path('creole.general')
assert grp.optimpl_get_group_type() == groups.family assert grp.impl_get_group_type() == groups.family
assert grp.optimpl_get_group_type() == 'family' assert grp.impl_get_group_type() == 'family'
assert isinstance(grp.optimpl_get_group_type(), groups.GroupType) assert isinstance(grp.impl_get_group_type(), groups.GroupType)
raises(TypeError, 'grp.optimpl_set_group_type(groups.default)') raises(TypeError, 'grp.impl_set_group_type(groups.default)')
def test_iter_on_groups(): def test_iter_on_groups():
@ -103,31 +103,31 @@ def test_groups_with_master():
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True) ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True) netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0]) interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
interface1.optimpl_set_group_type(groups.master) interface1.impl_set_group_type(groups.master)
assert interface1.optimpl_get_group_type() == groups.master assert interface1.impl_get_group_type() == groups.master
def test_groups_with_master_in_config(): def test_groups_with_master_in_config():
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True) ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True) netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0]) interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
interface1.optimpl_set_group_type(groups.master) interface1.impl_set_group_type(groups.master)
Config(interface1) Config(interface1)
assert interface1.optimpl_get_group_type() == groups.master assert interface1.impl_get_group_type() == groups.master
def test_allowed_groups(): def test_allowed_groups():
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True) ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True) netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0]) interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
raises(ValueError, "interface1.optimpl_set_group_type('toto')") raises(ValueError, "interface1.impl_set_group_type('toto')")
def test_master_not_valid_name(): def test_master_not_valid_name():
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True) ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True) netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
invalid_group = OptionDescription('interface1', '', [ip_admin_eth0, netmask_admin_eth0]) invalid_group = OptionDescription('interface1', '', [ip_admin_eth0, netmask_admin_eth0])
raises(ValueError, "invalid_group.optimpl_set_group_type(groups.master)") raises(ValueError, "invalid_group.impl_set_group_type(groups.master)")
def test_sub_group_in_master_group(): def test_sub_group_in_master_group():
@ -135,14 +135,14 @@ def test_sub_group_in_master_group():
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True) netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
subgroup = OptionDescription("subgroup", '', []) subgroup = OptionDescription("subgroup", '', [])
invalid_group = OptionDescription('ip_admin_eth0', '', [subgroup, ip_admin_eth0, netmask_admin_eth0]) invalid_group = OptionDescription('ip_admin_eth0', '', [subgroup, ip_admin_eth0, netmask_admin_eth0])
raises(ValueError, "invalid_group.optimpl_set_group_type(groups.master)") raises(ValueError, "invalid_group.impl_set_group_type(groups.master)")
def test_group_always_has_multis(): def test_group_always_has_multis():
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True) ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau") netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau")
group = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0]) group = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
raises(ValueError, "group.optimpl_set_group_type(groups.master)") raises(ValueError, "group.impl_set_group_type(groups.master)")
#____________________________________________________________ #____________________________________________________________
@ -150,11 +150,11 @@ def test_values_with_master_and_slaves():
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True) ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True) netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0]) interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
interface1.optimpl_set_group_type(groups.master) interface1.impl_set_group_type(groups.master)
maconfig = OptionDescription('toto', '', [interface1]) maconfig = OptionDescription('toto', '', [interface1])
cfg = Config(maconfig) cfg = Config(maconfig)
owner = cfg._cfgimpl_context._cfgimpl_settings.getowner() owner = cfg.cfgimpl_get_settings().getowner()
assert interface1.optimpl_get_group_type() == groups.master assert interface1.impl_get_group_type() == groups.master
assert cfg.getowner("ip_admin_eth0.ip_admin_eth0") == owners.default assert cfg.getowner("ip_admin_eth0.ip_admin_eth0") == owners.default
assert cfg.getowner("ip_admin_eth0.netmask_admin_eth0") == owners.default assert cfg.getowner("ip_admin_eth0.netmask_admin_eth0") == owners.default
assert cfg.ip_admin_eth0.netmask_admin_eth0 == [] assert cfg.ip_admin_eth0.netmask_admin_eth0 == []
@ -169,11 +169,11 @@ def test_reset_values_with_master_and_slaves():
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True) ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True) netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0]) interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
interface1.optimpl_set_group_type(groups.master) interface1.impl_set_group_type(groups.master)
maconfig = OptionDescription('toto', '', [interface1]) maconfig = OptionDescription('toto', '', [interface1])
cfg = Config(maconfig) cfg = Config(maconfig)
owner = cfg._cfgimpl_context._cfgimpl_settings.getowner() owner = cfg.cfgimpl_get_settings().getowner()
assert interface1.optimpl_get_group_type() == groups.master assert interface1.impl_get_group_type() == groups.master
assert cfg.getowner("ip_admin_eth0.ip_admin_eth0") == owners.default assert cfg.getowner("ip_admin_eth0.ip_admin_eth0") == owners.default
assert cfg.getowner("ip_admin_eth0.netmask_admin_eth0") == owners.default assert cfg.getowner("ip_admin_eth0.netmask_admin_eth0") == owners.default
cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145") cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145")
@ -190,7 +190,7 @@ def test_values_with_master_and_slaves_slave():
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True) ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True) netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0]) interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
interface1.optimpl_set_group_type(groups.master) interface1.impl_set_group_type(groups.master)
maconfig = OptionDescription('toto', '', [interface1]) maconfig = OptionDescription('toto', '', [interface1])
cfg = Config(maconfig) cfg = Config(maconfig)
assert cfg.ip_admin_eth0.netmask_admin_eth0 == [] assert cfg.ip_admin_eth0.netmask_admin_eth0 == []
@ -212,7 +212,7 @@ def test_values_with_master_and_slaves_master():
ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True) ip_admin_eth0 = StrOption('ip_admin_eth0', "ip réseau autorisé", multi=True)
netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True) netmask_admin_eth0 = StrOption('netmask_admin_eth0', "masque du sous-réseau", multi=True)
interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0]) interface1 = OptionDescription('ip_admin_eth0', '', [ip_admin_eth0, netmask_admin_eth0])
interface1.optimpl_set_group_type(groups.master) interface1.impl_set_group_type(groups.master)
maconfig = OptionDescription('toto', '', [interface1]) maconfig = OptionDescription('toto', '', [interface1])
cfg = Config(maconfig) cfg = Config(maconfig)
cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145") cfg.ip_admin_eth0.ip_admin_eth0.append("192.168.230.145")

54
test/test_slots.py Normal file
View File

@ -0,0 +1,54 @@
# coding: utf-8
import autopath
from py.test import raises
from tiramisu.config import Config, SubConfig
from tiramisu.option import ChoiceOption, BoolOption, IntOption, FloatOption, \
StrOption, OptionDescription, SymLinkOption, UnicodeOption
def test_slots_option():
c = BoolOption('a', '')
raises(AttributeError, "c.x = 1")
c = IntOption('a', '')
raises(AttributeError, "c.x = 1")
c = FloatOption('a', '')
raises(AttributeError, "c.x = 1")
c = StrOption('a', '')
raises(AttributeError, "c.x = 1")
c = SymLinkOption('b', c)
raises(AttributeError, "c.x = 1")
c = UnicodeOption('a', '')
raises(AttributeError, "c.x = 1")
c = ChoiceOption('a', '', ('a',))
raises(AttributeError, "c.x = 1")
c = OptionDescription('a', '', [])
raises(AttributeError, "c.x = 1")
def test_slots_config():
od1 = OptionDescription('a', '', [])
od2 = OptionDescription('a', '', [od1])
c = Config(od2)
raises(AttributeError, "c.x = 1")
raises(AttributeError, "c.cfgimpl_x = 1")
sc = c.a
assert isinstance(sc, SubConfig)
raises(AttributeError, "sc.x = 1")
raises(AttributeError, "sc.cfgimpl_x = 1")
def test_slots_setting():
od1 = OptionDescription('a', '', [])
od2 = OptionDescription('a', '', [od1])
c = Config(od2)
s = c.cfgimpl_get_settings()
raises(AttributeError, "s.x = 1")
def test_slots_value():
od1 = OptionDescription('a', '', [])
od2 = OptionDescription('a', '', [od1])
c = Config(od2)
v = c.cfgimpl_get_values()
raises(AttributeError, "v.x = 1")

View File

@ -22,15 +22,16 @@
# ____________________________________________________________ # ____________________________________________________________
#from inspect import getmembers, ismethod #from inspect import getmembers, ismethod
from tiramisu.error import PropertiesOptionError, ConfigError from tiramisu.error import PropertiesOptionError, ConfigError
from tiramisu.option import OptionDescription, Option, SymLinkOption from tiramisu.option import OptionDescription, Option, SymLinkOption, \
BaseInformation
from tiramisu.setting import groups, Setting from tiramisu.setting import groups, Setting
from tiramisu.value import Values from tiramisu.value import Values
from tiramisu.i18n import _ from tiramisu.i18n import _
class SubConfig(object): class SubConfig(BaseInformation):
"sub configuration management entry" "sub configuration management entry"
__slots__ = ('_cfgimpl_context', '_cfgimpl_descr') __slots__ = ('_impl_context', '_impl_descr')
def __init__(self, descr, context): def __init__(self, descr, context):
""" Configuration option management master class """ Configuration option management master class
@ -44,11 +45,11 @@ class SubConfig(object):
if not isinstance(descr, OptionDescription): if not isinstance(descr, OptionDescription):
raise ValueError(_('descr must be an optiondescription, not {0}' raise ValueError(_('descr must be an optiondescription, not {0}'
'').format(type(descr))) '').format(type(descr)))
self._cfgimpl_descr = descr self._impl_descr = descr
# sub option descriptions # sub option descriptions
if not isinstance(context, SubConfig): if not isinstance(context, SubConfig):
raise ValueError('context must be a SubConfig') raise ValueError('context must be a SubConfig')
self._cfgimpl_context = context self._impl_context = context
def cfgimpl_reset_cache(self, only_expired=False, only=('values', def cfgimpl_reset_cache(self, only_expired=False, only=('values',
'settings')): 'settings')):
@ -68,14 +69,14 @@ class SubConfig(object):
return self, path[-1] return self, path[-1]
def __hash__(self): def __hash__(self):
return hash(self.cfgimpl_get_description().optimpl_getkey(self)) return hash(self.cfgimpl_get_description().impl_getkey(self))
def __eq__(self, other): def __eq__(self, other):
"Config comparison" "Config comparison"
if not isinstance(other, Config): if not isinstance(other, Config):
return False return False
return self.cfgimpl_get_description().optimpl_getkey(self) == \ return self.cfgimpl_get_description().impl_getkey(self) == \
other.cfgimpl_get_description().optimpl_getkey(other) other.cfgimpl_get_description().impl_getkey(other)
def __ne__(self, other): def __ne__(self, other):
"Config comparison" "Config comparison"
@ -87,7 +88,7 @@ class SubConfig(object):
def __iter__(self): def __iter__(self):
"""Pythonesque way of parsing group's ordered options. """Pythonesque way of parsing group's ordered options.
iteration only on Options (not OptionDescriptions)""" iteration only on Options (not OptionDescriptions)"""
for child in self.cfgimpl_get_description().optimpl_getchildren(): for child in self.cfgimpl_get_description().impl_getchildren():
if not isinstance(child, OptionDescription): if not isinstance(child, OptionDescription):
try: try:
yield child._name, getattr(self, child._name) yield child._name, getattr(self, child._name)
@ -99,7 +100,7 @@ class SubConfig(object):
def iter_all(self): def iter_all(self):
"""A way of parsing options **and** groups. """A way of parsing options **and** groups.
iteration on Options and OptionDescriptions.""" iteration on Options and OptionDescriptions."""
for child in self.cfgimpl_get_description().optimpl_getchildren(): for child in self.cfgimpl_get_description().impl_getchildren():
try: try:
yield child._name, getattr(self, child._name) yield child._name, getattr(self, child._name)
except GeneratorExit: except GeneratorExit:
@ -120,11 +121,11 @@ class SubConfig(object):
if group_type is not None: if group_type is not None:
if not isinstance(group_type, groups.GroupType): if not isinstance(group_type, groups.GroupType):
raise TypeError(_("unknown group_type: {0}").format(group_type)) raise TypeError(_("unknown group_type: {0}").format(group_type))
for child in self.cfgimpl_get_description().optimpl_getchildren(): for child in self.cfgimpl_get_description().impl_getchildren():
if isinstance(child, OptionDescription): if isinstance(child, OptionDescription):
try: try:
if group_type is None or (group_type is not None and if group_type is None or (group_type is not None and
child.optimpl_get_group_type() child.impl_get_group_type()
== group_type): == group_type):
yield child._name, getattr(self, child._name) yield child._name, getattr(self, child._name)
except GeneratorExit: except GeneratorExit:
@ -148,25 +149,25 @@ class SubConfig(object):
__repr__ = __str__ __repr__ = __str__
def cfgimpl_get_context(self): def cfgimpl_get_context(self):
return self._cfgimpl_context return self._impl_context
def cfgimpl_get_description(self): def cfgimpl_get_description(self):
if self._cfgimpl_descr is None: if self._impl_descr is None:
raise ConfigError(_('no optiondescription for this config (may be MetaConfig without meta)')) raise ConfigError(_('no optiondescription for this config (may be MetaConfig without meta)'))
else: else:
return self._cfgimpl_descr return self._impl_descr
def cfgimpl_get_settings(self): def cfgimpl_get_settings(self):
return self.cfgimpl_get_context()._cfgimpl_settings return self.cfgimpl_get_context()._impl_settings
def cfgimpl_get_values(self): def cfgimpl_get_values(self):
return self.cfgimpl_get_context()._cfgimpl_values return self.cfgimpl_get_context()._impl_values
# ____________________________________________________________ # ____________________________________________________________
# attribute methods # attribute methods
def __setattr__(self, name, value): def __setattr__(self, name, value):
"attribute notation mechanism for the setting of the value of an option" "attribute notation mechanism for the setting of the value of an option"
if name.startswith('_cfgimpl_'): if name.startswith('_impl_'):
#self.__dict__[name] = value #self.__dict__[name] = value
object.__setattr__(self, name, value) object.__setattr__(self, name, value)
return return
@ -182,7 +183,7 @@ class SubConfig(object):
force_permissive=force_permissive) force_permissive=force_permissive)
else: else:
context = self.cfgimpl_get_context() context = self.cfgimpl_get_context()
path = context.cfgimpl_get_description().optimpl_get_path_by_opt(child._opt) path = context.cfgimpl_get_description().impl_get_path_by_opt(child._opt)
context._setattr(path, value, force_permissive=force_permissive) context._setattr(path, value, force_permissive=force_permissive)
def __delattr__(self, name): def __delattr__(self, name):
@ -210,14 +211,15 @@ class SubConfig(object):
force_properties=force_properties, force_properties=force_properties,
validate=validate) validate=validate)
# special attributes # special attributes
if name.startswith('_cfgimpl_') or name.startswith('cfgimpl_'): if name.startswith('_impl_') or name.startswith('cfgimpl_') \
or name.startswith('impl_'):
# if it were in __dict__ it would have been found already # if it were in __dict__ it would have been found already
return object.__getattribute__(self, name) return object.__getattribute__(self, name)
opt_or_descr = getattr(self.cfgimpl_get_description(), name) opt_or_descr = getattr(self.cfgimpl_get_description(), name)
# symlink options # symlink options
if isinstance(opt_or_descr, SymLinkOption): if isinstance(opt_or_descr, SymLinkOption):
context = self.cfgimpl_get_context() context = self.cfgimpl_get_context()
path = context.cfgimpl_get_description().optimpl_get_path_by_opt(opt_or_descr._opt) path = context.cfgimpl_get_description().impl_get_path_by_opt(opt_or_descr._opt)
return context._getattr(path, validate=validate, return context._getattr(path, validate=validate,
force_properties=force_properties, force_properties=force_properties,
force_permissive=force_permissive) force_permissive=force_permissive)
@ -371,7 +373,7 @@ class SubConfig(object):
type_='path', type_='path',
_subpath=mypath): _subpath=mypath):
path = '.'.join(path.split('.')[:-1]) path = '.'.join(path.split('.')[:-1])
opt = self.cfgimpl_get_context().cfgimpl_get_description().optimpl_get_opt_by_path(path) opt = self.cfgimpl_get_context().cfgimpl_get_description().impl_get_opt_by_path(path)
if mypath is not None: if mypath is not None:
if mypath == path: if mypath == path:
withoption = None withoption = None
@ -387,7 +389,7 @@ class SubConfig(object):
self._make_sub_dict(opt, path, pathsvalues, _currpath, flatten) self._make_sub_dict(opt, path, pathsvalues, _currpath, flatten)
#withoption can be set to None below ! #withoption can be set to None below !
if withoption is None: if withoption is None:
for opt in self.cfgimpl_get_description().optimpl_getchildren(): for opt in self.cfgimpl_get_description().impl_getchildren():
path = opt._name path = opt._name
self._make_sub_dict(opt, path, pathsvalues, _currpath, flatten) self._make_sub_dict(opt, path, pathsvalues, _currpath, flatten)
if _currpath == []: if _currpath == []:
@ -416,14 +418,14 @@ class SubConfig(object):
def cfgimpl_get_path(self): def cfgimpl_get_path(self):
descr = self.cfgimpl_get_description() descr = self.cfgimpl_get_description()
context_descr = self.cfgimpl_get_context().cfgimpl_get_description() context_descr = self.cfgimpl_get_context().cfgimpl_get_description()
return context_descr.optimpl_get_path_by_opt(descr) return context_descr.impl_get_path_by_opt(descr)
class ConfigCommon(SubConfig): class ConfigCommon(SubConfig):
__slots__ = ('_cfgimpl_values', '_cfgimpl_settings', '_cfgimpl_meta') __slots__ = ('_impl_values', '_impl_settings', '_impl_meta')
def _cfgimpl_build_all_paths(self): def _impl_build_all_paths(self):
self.cfgimpl_get_description().optimpl_build_cache() self.cfgimpl_get_description().impl_build_cache()
def read_only(self): def read_only(self):
self.cfgimpl_get_settings().read_only() self.cfgimpl_get_settings().read_only()
@ -432,7 +434,7 @@ class ConfigCommon(SubConfig):
self.cfgimpl_get_settings().read_write() self.cfgimpl_get_settings().read_write()
def getowner(self, path): def getowner(self, path):
opt = self.cfgimpl_get_description().optimpl_get_opt_by_path(path) opt = self.cfgimpl_get_description().impl_get_opt_by_path(path)
return self.cfgimpl_get_values().getowner(opt) return self.cfgimpl_get_values().getowner(opt)
def unwrap_from_path(self, path): def unwrap_from_path(self, path):
@ -451,7 +453,7 @@ class ConfigCommon(SubConfig):
return None return None
def cfgimpl_get_meta(self): def cfgimpl_get_meta(self):
return self._cfgimpl_meta return self._impl_meta
# ____________________________________________________________ # ____________________________________________________________
@ -467,11 +469,12 @@ class Config(ConfigCommon):
:param context: the current root config :param context: the current root config
:type context: `Config` :type context: `Config`
""" """
self._cfgimpl_settings = Setting(self) self._impl_settings = Setting(self)
self._cfgimpl_values = Values(self) self._impl_values = Values(self)
super(Config, self).__init__(descr, self) # , slots) super(Config, self).__init__(descr, self)
self._cfgimpl_build_all_paths() self._impl_build_all_paths()
self._cfgimpl_meta = None self._impl_meta = None
self._impl_informations = {}
def cfgimpl_reset_cache(self, only_expired=False, only=('values', 'settings')): def cfgimpl_reset_cache(self, only_expired=False, only=('values', 'settings')):
if 'values' in only: if 'values' in only:
@ -481,30 +484,30 @@ class Config(ConfigCommon):
class MetaConfig(ConfigCommon): class MetaConfig(ConfigCommon):
__slots__ = ('_cfgimpl_children',) __slots__ = ('_impl_children',)
def __init__(self, children, meta=True): def __init__(self, children, meta=True):
if not isinstance(children, list): if not isinstance(children, list):
raise ValueError(_("metaconfig's children must be a list")) raise ValueError(_("metaconfig's children must be a list"))
self._cfgimpl_descr = None self._impl_descr = None
if meta: if meta:
for child in children: for child in children:
if not isinstance(child, ConfigCommon): if not isinstance(child, ConfigCommon):
raise ValueError(_("metaconfig's children must be Config, not {0}" raise ValueError(_("metaconfig's children must be Config, not {0}"
"".format(type(child)))) "".format(type(child))))
if self._cfgimpl_descr is None: if self._impl_descr is None:
self._cfgimpl_descr = child.cfgimpl_get_description() self._impl_descr = child.cfgimpl_get_description()
elif not self._cfgimpl_descr is child.cfgimpl_get_description(): elif not self._impl_descr is child.cfgimpl_get_description():
raise ValueError(_('all config in MetaConfig must have same ' raise ValueError(_('all config in MetaConfig must have same '
'optiondescription')) 'optiondescription'))
if child.cfgimpl_get_meta() is not None: if child.cfgimpl_get_meta() is not None:
raise ValueError(_("child has already a metaconfig's")) raise ValueError(_("child has already a metaconfig's"))
child._cfgimpl_meta = self child._impl_meta = self
self._cfgimpl_children = children self._impl_children = children
self._cfgimpl_settings = Setting(self) self._impl_settings = Setting(self)
self._cfgimpl_values = Values(self) self._impl_values = Values(self)
self._cfgimpl_meta = None self._impl_meta = None
def cfgimpl_get_context(self): def cfgimpl_get_context(self):
return self return self
@ -514,11 +517,11 @@ class MetaConfig(ConfigCommon):
self.cfgimpl_get_values().reset_cache(only_expired=only_expired) self.cfgimpl_get_values().reset_cache(only_expired=only_expired)
if 'settings' in only: if 'settings' in only:
self.cfgimpl_get_settings().reset_cache(only_expired=only_expired) self.cfgimpl_get_settings().reset_cache(only_expired=only_expired)
for child in self._cfgimpl_children: for child in self._impl_children:
child.cfgimpl_reset_cache(only_expired=only_expired, only=only) child.cfgimpl_reset_cache(only_expired=only_expired, only=only)
def set_contexts(self, path, value): def set_contexts(self, path, value):
for child in self._cfgimpl_children: for child in self._impl_children:
try: try:
if not isinstance(child, MetaConfig): if not isinstance(child, MetaConfig):
setattr(child, path, value) setattr(child, path, value)
@ -537,7 +540,7 @@ class MetaConfig(ConfigCommon):
check_properties=False) check_properties=False)
except ConfigError: except ConfigError:
pass pass
for child in self._cfgimpl_children: for child in self._impl_children:
try: try:
if not isinstance(child, MetaConfig): if not isinstance(child, MetaConfig):
if bypath is not None: if bypath is not None:
@ -570,9 +573,9 @@ def mandatory_warnings(config):
""" """
#if value in cache, properties are not calculated #if value in cache, properties are not calculated
config.cfgimpl_reset_cache(only=('values',)) config.cfgimpl_reset_cache(only=('values',))
for path in config.cfgimpl_get_description().optimpl_getpaths(include_groups=True): for path in config.cfgimpl_get_description().impl_getpaths(include_groups=True):
try: try:
config._getattr(path, force_properties=('mandatory',)) config._getattr(path, force_properties=frozenset(('mandatory',)))
except PropertiesOptionError, err: except PropertiesOptionError, err:
if err.proptype == ['mandatory']: if err.proptype == ['mandatory']:
yield path yield path

View File

@ -31,9 +31,9 @@ from tiramisu.i18n import _
from tiramisu.autolib import carry_out_calculation from tiramisu.autolib import carry_out_calculation
name_regexp = re.compile(r'^\d+') name_regexp = re.compile(r'^\d+')
forbidden_names = ['iter_all', 'iter_group', 'find', 'find_first', forbidden_names = ('iter_all', 'iter_group', 'find', 'find_first',
'make_dict', 'unwrap_from_path', 'read_only', 'make_dict', 'unwrap_from_path', 'read_only',
'read_write', 'getowner', 'set_contexts'] 'read_write', 'getowner', 'set_contexts')
def valid_name(name): def valid_name(name):
@ -43,7 +43,7 @@ def valid_name(name):
return False return False
if re.match(name_regexp, name) is None and not name.startswith('_') \ if re.match(name_regexp, name) is None and not name.startswith('_') \
and name not in forbidden_names \ and name not in forbidden_names \
and not name.startswith('optimpl_') \ and not name.startswith('impl_') \
and not name.startswith('cfgimpl_'): and not name.startswith('cfgimpl_'):
return True return True
else: else:
@ -53,24 +53,24 @@ def valid_name(name):
class BaseInformation(object): class BaseInformation(object):
__slots__ = ('_informations',) __slots__ = ('_impl_informations',)
def optimpl_set_information(self, key, value): def impl_set_information(self, key, value):
"""updates the information's attribute """updates the information's attribute
(wich is a dictionnary) (wich is a dictionnary)
:param key: information's key (ex: "help", "doc" :param key: information's key (ex: "help", "doc"
:param value: information's value (ex: "the help string") :param value: information's value (ex: "the help string")
""" """
self._informations[key] = value self._impl_informations[key] = value
def optimpl_get_information(self, key, default=None): def impl_get_information(self, key, default=None):
"""retrieves one information's item """retrieves one information's item
:param key: the item string (ex: "help") :param key: the item string (ex: "help")
""" """
if key in self._informations: if key in self._impl_informations:
return self._informations[key] return self._impl_informations[key]
elif default is not None: elif default is not None:
return default return default
else: else:
@ -112,8 +112,8 @@ class Option(BaseInformation):
if not valid_name(name): if not valid_name(name):
raise ValueError(_("invalid name: {0} for option").format(name)) raise ValueError(_("invalid name: {0} for option").format(name))
self._name = name self._name = name
self._informations = {} self._impl_informations = {}
self.optimpl_set_information('doc', doc) self.impl_set_information('doc', doc)
validate_requires_arg(requires, self._name) validate_requires_arg(requires, self._name)
self._requires = requires self._requires = requires
self._multi = multi self._multi = multi
@ -150,37 +150,23 @@ class Option(BaseInformation):
if self._multi: if self._multi:
if default is None: if default is None:
default = [] default = []
#if not isinstance(default, list):
# raise ValidateError("invalid default value {0} "
# "for option {1} : not list type"
# "".format(str(default), name))
if not self.optimpl_validate(default):
raise ValueError(_("invalid default value {0} "
"for option {1}"
"").format(str(default), name))
self._multitype = multitypes.default self._multitype = multitypes.default
self._default_multi = default_multi self._default_multi = default_multi
else: self.impl_validate(default)
if default is not None and not self.optimpl_validate(default):
raise ValueError(_("invalid default value {0} "
"for option {1}").format(str(default), name))
self._default = default self._default = default
if properties is None: if properties is None:
properties = () properties = tuple()
if not isinstance(properties, tuple): if not isinstance(properties, tuple):
raise TypeError(_('invalid properties type {0} for {1},' raise TypeError(_('invalid properties type {0} for {1},'
' must be a tuple').format(type(properties), self._name)) ' must be a tuple').format(type(properties), self._name))
self._properties = properties # 'hidden', 'disabled'... self._properties = set(properties) # 'hidden', 'disabled'...
def __eq__(self, other): def __eq__(self, other):
"Option comparison" "Option comparison"
if not isinstance(other, Option): if not isinstance(other, Option):
return False return False
a = list(self.__slots__ + Option.__slots__ + BaseInformation.__slots__) slots = list(self.__slots__ + Option.__slots__ + BaseInformation.__slots__)
#a.remove('_default_multi') for var in slots:
a.remove('_master_slaves')
a.remove('_multitype')
for var in a:
try: try:
val1 = getattr(self, var) val1 = getattr(self, var)
not_in1 = False not_in1 = False
@ -203,7 +189,10 @@ class Option(BaseInformation):
return False return False
return not self == other return not self == other
def optimpl_validate(self, value, context=None, validate=True): def _launch_consistency(self, func, opt, value, context, index, opts):
return getattr(self, func)(opt, value, context, index, opts)
def impl_validate(self, value, context=None, validate=True):
""" """
:param value: the option's value :param value: the option's value
:param validate: if true enables ``self._validator`` validation :param validate: if true enables ``self._validator`` validation
@ -217,121 +206,114 @@ class Option(BaseInformation):
def val_validator(): def val_validator():
#add current value has first argument #add current value has first argument
if self.optimpl_is_multi(): if self.impl_is_multi():
for val in value: for val in value:
if not _val_validator(val): if not _val_validator(val):
return False return False
return True
else: else:
return _val_validator(val) return _val_validator(value)
return True
# generic calculation # generic calculation
if context is not None: if context is not None:
cons = context.cfgimpl_get_description() descr = context.cfgimpl_get_description()
else:
cons = None
if not self._multi: if not self._multi:
# None allows the reset of the value if value is not None and ((validate and
if value is not None: self._validator is not None and
# customizing the validator not val_validator()) or
if validate and self._validator is not None and \ not self._validate(value)):
not self._validator[0](value, **self._validator[1]): raise ValueError(_("invalid value {0} for option {1}"
return False "").format(value, self._name))
if not self._validate(value): if context is not None:
return False descr._valid_consistency(self, value, context, None)
if cons is not None:
return cons._valid_consistency(self, value, context, None)
else: else:
if not isinstance(value, list): if not isinstance(value, list):
raise ValueError(_("invalid value {0} " raise ValueError(_("invalid value {0} for option {1} "
"for option {1} which must be a list" "which must be a list").format(value,
"").format(value, self._name)) self._name))
for index in range(0, len(value)): for index in range(0, len(value)):
val = value[index] val = value[index]
# None allows the reset of the value if val is not None and ((validate and
if val is not None: self._validator is not None and
# customizing the validator not val_validator()) or
if validate and self._validator is not None and \ not self._validate(val)):
not val_validator(): raise ValueError(_("invalid value {0} for option {1}"
return False "").format(value, self._name))
if not self._validate(val): if context is not None:
return False descr._valid_consistency(self, val, context, index)
if cons is not None and not cons._valid_consistency(self,
val,
context,
index):
return False
return True
def optimpl_getdefault(self, default_multi=False): def impl_getdefault(self, default_multi=False):
"accessing the default value" "accessing the default value"
if not default_multi or not self.optimpl_is_multi(): if not default_multi or not self.impl_is_multi():
return self._default return self._default
else: else:
return self.getdefault_multi() return self.getdefault_multi()
def optimpl_getdefault_multi(self): def impl_getdefault_multi(self):
"accessing the default value for a multi" "accessing the default value for a multi"
return self._default_multi return self._default_multi
def optimpl_get_multitype(self): def impl_get_multitype(self):
return self._multitype return self._multitype
def optimpl_get_master_slaves(self): def impl_get_master_slaves(self):
return self._master_slaves return self._master_slaves
def optimpl_is_empty_by_default(self): def impl_is_empty_by_default(self):
"no default value has been set yet" "no default value has been set yet"
if ((not self.optimpl_is_multi() and self._default is None) or if ((not self.impl_is_multi() and self._default is None) or
(self.optimpl_is_multi() and (self._default == [] or None in self._default))): (self.impl_is_multi() and (self._default == [] or None in self._default))):
return True return True
return False return False
def optimpl_getdoc(self): def impl_getdoc(self):
"accesses the Option's doc" "accesses the Option's doc"
return self.optimpl_get_information('doc') return self.impl_get_information('doc')
def optimpl_has_callback(self): def impl_has_callback(self):
"to know if a callback has been defined or not" "to know if a callback has been defined or not"
if self._callback is None: if self._callback is None:
return False return False
else: else:
return True return True
def optimpl_getkey(self, value): def impl_getkey(self, value):
return value return value
def optimpl_is_multi(self): def impl_is_multi(self):
return self._multi return self._multi
def optimpl_add_consistency(self, func, opts): def impl_add_consistency(self, func, opts):
pass
if self._consistencies is None: if self._consistencies is None:
self._consistencies = [] self._consistencies = []
if self not in opts: if self not in opts:
opts = list(opts) opts = list(opts)
opts.append(self) opts.append(self)
opts = tuple(opts) opts = tuple(opts)
self._consistencies.append(('_cons_{}'.format(func), opts)) func = '_cons_{}'.format(func)
for opt in opts:
if opt != self:
self._launch_consistency(func, opt, self.impl_getdefault(), None, None, opts)
self._consistencies.append((func, opts))
self.impl_validate(self.impl_getdefault(), None)
def _cons_not_equal(self, opt, value, context, index, opts): def _cons_not_equal(self, opt, value, context, index, opts):
values = [value] values = [value]
descr = context.cfgimpl_get_description() if context is not None:
descr = context.cfgimpl_get_description()
for opt_ in opts: for opt_ in opts:
if opt_ is not opt: if opt_ is not opt:
path = descr.optimpl_get_path_by_opt(opt_) if context is not None:
val = context._getattr(path, validate=False) path = descr.impl_get_path_by_opt(opt_)
val = context._getattr(path, validate=False)
else:
val = opt.impl_getdefault()
if val is not None: if val is not None:
if val in values: if val in values:
return False raise ValueError(_("invalid value {0} for option {1} "
"must be different as {2} option"
"").format(val, self._name,
opt_._name))
values.append(val) values.append(val)
return True
def _cons_lower(self, value):
try:
return value.islower()
except AttributeError:
#no "islower" attribute
return False
class ChoiceOption(Option): class ChoiceOption(Option):
@ -359,10 +341,10 @@ class ChoiceOption(Option):
validator_args=validator_args, validator_args=validator_args,
properties=properties) properties=properties)
def optimpl_get_values(self): def impl_get_values(self):
return self._values return self._values
def optimpl_is_openvalues(self): def impl_is_openvalues(self):
return self._open_values return self._open_values
def _validate(self, value): def _validate(self, value):
@ -418,8 +400,11 @@ class SymLinkOption(object):
_opt_type = 'symlink' _opt_type = 'symlink'
_consistencies = None _consistencies = None
def __init__(self, name, path, opt): def __init__(self, name, opt):
self._name = name self._name = name
if not isinstance(opt, Option):
raise ValueError(_('malformed symlinkoption '
'must be an option for symlink {0}').format(name))
self._opt = opt self._opt = opt
def __getattr__(self, name): def __getattr__(self, name):
@ -474,31 +459,6 @@ class NetmaskOption(Option):
__slots__ = ('_opt_type',) __slots__ = ('_opt_type',)
_opt_type = 'netmask' _opt_type = 'netmask'
def __init__(self, name, doc, default=None, default_multi=None,
requires=None, multi=False, callback=None,
callback_params=None, validator=None, validator_args=None,
properties=None, opt_ip=None):
if opt_ip is not None and not isinstance(opt_ip, IPOption) and \
not isinstance(opt_ip, NetworkOption):
raise TypeError(_('opt_ip must be a IPOption not {}').format(type(opt_ip)))
super(NetmaskOption, self).__init__(name, doc, default=default,
default_multi=default_multi,
callback=callback,
callback_params=callback_params,
requires=requires,
multi=multi,
validator=validator,
validator_args=validator_args,
properties=properties)
if opt_ip is None:
pass
elif isinstance(opt_ip, IPOption):
self._consistencies = [('cons_ip_netmask', (self, opt_ip))]
elif isinstance(opt_ip, NetworkOption):
self._consistencies = [('cons_network_netmask', (self, opt_ip))]
else:
raise TypeError(_('unknown type for opt_ip'))
def _validate(self, value): def _validate(self, value):
try: try:
IP('0.0.0.0/{}'.format(value)) IP('0.0.0.0/{}'.format(value))
@ -508,36 +468,61 @@ class NetmaskOption(Option):
def _cons_network_netmask(self, opt, value, context, index, opts): def _cons_network_netmask(self, opt, value, context, index, opts):
#opts must be (netmask, network) options #opts must be (netmask, network) options
return self._cons_netmask(opt, value, context, index, opts, False) self.__cons_netmask(opt, value, context, index, opts, False)
def _cons_ip_netmask(self, opt, value, context, index, opts): def _cons_ip_netmask(self, opt, value, context, index, opts):
#opts must be (netmask, ip) options #opts must be (netmask, ip) options
return self._cons_netmask(opt, value, context, index, opts, True) self.__cons_netmask(opt, value, context, index, opts, True)
def __cons_netmask(self, opt, value, context, index, opts, make_net): def __cons_netmask(self, opt, value, context, index, opts, make_net):
opt_netmask, opt_ipnetwork = opts opt_netmask, opt_ipnetwork = opts
descr = context.cfgimpl_get_description() if context is not None:
descr = context.cfgimpl_get_description()
if opt is opt_ipnetwork: if opt is opt_ipnetwork:
val_ipnetwork = value val_ipnetwork = value
path = descr.optimpl_get_path_by_opt(opt_netmask) if context is not None:
val_netmask = context._getattr(path, validate=False) path = descr.impl_get_path_by_opt(opt_netmask)
if opt_netmask.optimpl_is_multi(): val_netmask = context._getattr(path, validate=False)
else:
val_netmask = opt_netmask.impl_getdefault()
if opt_netmask.impl_is_multi():
val_netmask = val_netmask[index] val_netmask = val_netmask[index]
if val_netmask is None:
return True
else: else:
val_netmask = value val_netmask = value
path = descr.optimpl_get_path_by_opt(opt_ipnetwork) if context is not None:
val_ipnetwork = getattr(context, path) path = descr.impl_get_path_by_opt(opt_ipnetwork)
if opt_ipnetwork.optimpl_is_multi(): val_ipnetwork = context._getattr(path, validate=False)
else:
val_ipnetwork = opt_ipnetwork.impl_getdefault()
if opt_ipnetwork.impl_is_multi():
val_ipnetwork = val_ipnetwork[index] val_ipnetwork = val_ipnetwork[index]
if val_ipnetwork is None: if None not in (val_ipnetwork, val_netmask):
return True msg = None
try: try:
IP('{}/{}'.format(val_ipnetwork, val_netmask, make_net=make_net)) ip = IP('{0}/{1}'.format(val_ipnetwork, val_netmask),
return True make_net=make_net)
except ValueError: #if cidr == 32, ip same has network
return False if ip.prefixlen() != 32:
try:
IP('{0}/{1}'.format(val_ipnetwork, val_netmask),
make_net=not make_net)
except ValueError:
if not make_net:
msg = _("invalid network {0} ({1}) with netmask {2} ({3}),"
" this network is an ip")
else:
if make_net:
msg = _("invalid ip {0} ({1}) with netmask {2} ({3}),"
" this ip is a network")
except ValueError:
if make_net:
msg = _("invalid ip {0} ({1}) with netmask {2} ({3})")
else:
msg = _("invalid network {0} ({1}) with netmask {2} ({3})")
if msg is not None:
raise ValueError(msg.format(val_ipnetwork, opt_ipnetwork._name,
val_netmask, opt_netmask._name))
class DomainnameOption(Option): class DomainnameOption(Option):
@ -553,15 +538,15 @@ class DomainnameOption(Option):
#hostname: to identify the device #hostname: to identify the device
#domainname: #domainname:
#fqdn: with tld, not supported yet #fqdn: with tld, not supported yet
super(NetmaskOption, self).__init__(name, doc, default=default, super(DomainnameOption, self).__init__(name, doc, default=default,
default_multi=default_multi, default_multi=default_multi,
callback=callback, callback=callback,
callback_params=callback_params, callback_params=callback_params,
requires=requires, requires=requires,
multi=multi, multi=multi,
validator=validator, validator=validator,
validator_args=validator_args, validator_args=validator_args,
properties=properties) properties=properties)
if type_ not in ['netbios', 'hostname', 'domainname']: if type_ not in ['netbios', 'hostname', 'domainname']:
raise ValueError(_('unknown type_ {0} for hostname').format(type_)) raise ValueError(_('unknown type_ {0} for hostname').format(type_))
self._type = type_ self._type = type_
@ -583,8 +568,13 @@ class DomainnameOption(Option):
elif self._type == 'domainname': elif self._type == 'domainname':
length = 255 length = 255
extrachar = '\.' extrachar = '\.'
regexp = r'^[a-zA-Z]([a-zA-Z\d-{0}]{{,{1}}})*[a-zA-Z\d]$'.format( if '.' not in value:
extrachar, length - 2) raise ValueError(_("invalid value for {0}, must have dot"
"").format(self._name))
if len(value) > length:
raise ValueError(_("invalid value's length for {0} (max {1})"
"").format(self._name, length))
regexp = r'^[a-z]([a-z\d{0}-])*[a-z\d]$'.format(extrachar)
return re.match(regexp, value) is not None return re.match(regexp, value) is not None
@ -593,7 +583,7 @@ class OptionDescription(BaseInformation):
__slots__ = ('_name', '_requires', '_cache_paths', '_group_type', __slots__ = ('_name', '_requires', '_cache_paths', '_group_type',
'_properties', '_children', '_consistencies') '_properties', '_children', '_consistencies')
def __init__(self, name, doc, children, requires=None, properties=()): def __init__(self, name, doc, children, requires=None, properties=None):
""" """
:param children: is a list of option descriptions (including :param children: is a list of option descriptions (including
``OptionDescription`` instances for nested namespaces). ``OptionDescription`` instances for nested namespaces).
@ -601,15 +591,15 @@ class OptionDescription(BaseInformation):
if not valid_name(name): if not valid_name(name):
raise ValueError(_("invalid name: {0} for option descr").format(name)) raise ValueError(_("invalid name: {0} for option descr").format(name))
self._name = name self._name = name
self._informations = {} self._impl_informations = {}
self.optimpl_set_information('doc', doc) self.impl_set_information('doc', doc)
child_names = [child._name for child in children] child_names = [child._name for child in children]
#better performance like this #better performance like this
valid_child = copy(child_names) valid_child = copy(child_names)
valid_child.sort() valid_child.sort()
old = None old = None
for child in valid_child: for child in valid_child:
if child == old: if id(child) == id(old):
raise ConflictError(_('duplicate option name: ' raise ConflictError(_('duplicate option name: '
'{0}').format(child)) '{0}').format(child))
old = child old = child
@ -618,15 +608,17 @@ class OptionDescription(BaseInformation):
self._requires = requires self._requires = requires
self._cache_paths = None self._cache_paths = None
self._consistencies = None self._consistencies = None
if properties is None:
properties = tuple()
if not isinstance(properties, tuple): if not isinstance(properties, tuple):
raise TypeError(_('invalid properties type {0} for {1},' raise TypeError(_('invalid properties type {0} for {1},'
' must be a tuple').format(type(properties), self._name)) ' must be a tuple').format(type(properties), self._name))
self._properties = properties # 'hidden', 'disabled'... self._properties = set(properties) # 'hidden', 'disabled'...
# the group_type is useful for filtering OptionDescriptions in a config # the group_type is useful for filtering OptionDescriptions in a config
self._group_type = groups.default self._group_type = groups.default
def optimpl_getdoc(self): def impl_getdoc(self):
return self.optimpl_get_information('doc') return self.impl_get_information('doc')
def __getattr__(self, name): def __getattr__(self, name):
try: try:
@ -635,32 +627,32 @@ class OptionDescription(BaseInformation):
raise AttributeError(_('unknown Option {} in OptionDescription {}' raise AttributeError(_('unknown Option {} in OptionDescription {}'
'').format(name, self._name)) '').format(name, self._name))
def optimpl_getkey(self, config): def impl_getkey(self, config):
return tuple([child.optimpl_getkey(getattr(config, child._name)) return tuple([child.impl_getkey(getattr(config, child._name))
for child in self.optimpl_getchildren()]) for child in self.impl_getchildren()])
def optimpl_getpaths(self, include_groups=False, _currpath=None): def impl_getpaths(self, include_groups=False, _currpath=None):
"""returns a list of all paths in self, recursively """returns a list of all paths in self, recursively
_currpath should not be provided (helps with recursion) _currpath should not be provided (helps with recursion)
""" """
if _currpath is None: if _currpath is None:
_currpath = [] _currpath = []
paths = [] paths = []
for option in self.optimpl_getchildren(): for option in self.impl_getchildren():
attr = option._name attr = option._name
if isinstance(option, OptionDescription): if isinstance(option, OptionDescription):
if include_groups: if include_groups:
paths.append('.'.join(_currpath + [attr])) paths.append('.'.join(_currpath + [attr]))
paths += option.optimpl_getpaths(include_groups=include_groups, paths += option.impl_getpaths(include_groups=include_groups,
_currpath=_currpath + [attr]) _currpath=_currpath + [attr])
else: else:
paths.append('.'.join(_currpath + [attr])) paths.append('.'.join(_currpath + [attr]))
return paths return paths
def optimpl_getchildren(self): def impl_getchildren(self):
return self._children[1] return self._children[1]
def optimpl_build_cache(self, cache_path=None, cache_option=None, _currpath=None, _consistencies=None): def impl_build_cache(self, cache_path=None, cache_option=None, _currpath=None, _consistencies=None):
if _currpath is None and self._cache_paths is not None: if _currpath is None and self._cache_paths is not None:
return return
if _currpath is None: if _currpath is None:
@ -672,7 +664,7 @@ class OptionDescription(BaseInformation):
if cache_path is None: if cache_path is None:
cache_path = [self._name] cache_path = [self._name]
cache_option = [self] cache_option = [self]
for option in self.optimpl_getchildren(): for option in self.impl_getchildren():
attr = option._name attr = option._name
if attr.startswith('_cfgimpl'): if attr.startswith('_cfgimpl'):
continue continue
@ -686,7 +678,7 @@ class OptionDescription(BaseInformation):
_consistencies.setdefault(opt, []).append((func, opts)) _consistencies.setdefault(opt, []).append((func, opts))
else: else:
_currpath.append(attr) _currpath.append(attr)
option.optimpl_build_cache(cache_path, cache_option, _currpath, _consistencies) option.impl_build_cache(cache_path, cache_option, _currpath, _consistencies)
_currpath.pop() _currpath.pop()
if save: if save:
#valid no duplicated option #valid no duplicated option
@ -694,27 +686,27 @@ class OptionDescription(BaseInformation):
valid_child.sort() valid_child.sort()
old = None old = None
for child in valid_child: for child in valid_child:
if child == old: if id(child) == id(old):
raise ConflictError(_('duplicate option: ' raise ConflictError(_('duplicate option: '
'{0}').format(child)) '{0}').format(child))
old = child old = child
self._cache_paths = (tuple(cache_option), tuple(cache_path)) self._cache_paths = (tuple(cache_option), tuple(cache_path))
self._consistencies = _consistencies self._consistencies = _consistencies
def optimpl_get_opt_by_path(self, path): def impl_get_opt_by_path(self, path):
try: try:
return self._cache_paths[0][self._cache_paths[1].index(path)] return self._cache_paths[0][self._cache_paths[1].index(path)]
except ValueError: except ValueError:
raise AttributeError(_('no option for path {}').format(path)) raise AttributeError(_('no option for path {}').format(path))
def optimpl_get_path_by_opt(self, opt): def impl_get_path_by_opt(self, opt):
try: try:
return self._cache_paths[1][self._cache_paths[0].index(opt)] return self._cache_paths[1][self._cache_paths[0].index(opt)]
except ValueError: except ValueError:
raise AttributeError(_('no option {} found').format(opt)) raise AttributeError(_('no option {} found').format(opt))
# ____________________________________________________________ # ____________________________________________________________
def optimpl_set_group_type(self, group_type): def impl_set_group_type(self, group_type):
"""sets a given group object to an OptionDescription """sets a given group object to an OptionDescription
:param group_type: an instance of `GroupType` or `MasterGroupType` :param group_type: an instance of `GroupType` or `MasterGroupType`
@ -731,11 +723,11 @@ class OptionDescription(BaseInformation):
#for collect all slaves #for collect all slaves
slaves = [] slaves = []
master = None master = None
for child in self.optimpl_getchildren(): for child in self.impl_getchildren():
if isinstance(child, OptionDescription): if isinstance(child, OptionDescription):
raise ValueError(_("master group {} shall not have " raise ValueError(_("master group {} shall not have "
"a subgroup").format(self._name)) "a subgroup").format(self._name))
if not child.optimpl_is_multi(): if not child.impl_is_multi():
raise ValueError(_("not allowed option {0} in group {1}" raise ValueError(_("not allowed option {0} in group {1}"
": this option is not a multi" ": this option is not a multi"
"").format(child._name, self._name)) "").format(child._name, self._name))
@ -749,7 +741,7 @@ class OptionDescription(BaseInformation):
raise ValueError(_('master group with wrong master name for {}' raise ValueError(_('master group with wrong master name for {}'
'').format(self._name)) '').format(self._name))
master._master_slaves = tuple(slaves) master._master_slaves = tuple(slaves)
for child in self.optimpl_getchildren(): for child in self.impl_getchildren():
if child != master: if child != master:
child._master_slaves = master child._master_slaves = master
child._multitype = multitypes.slave child._multitype = multitypes.slave
@ -759,15 +751,17 @@ class OptionDescription(BaseInformation):
else: else:
raise ValueError(_('not allowed group_type : {0}').format(group_type)) raise ValueError(_('not allowed group_type : {0}').format(group_type))
def optimpl_get_group_type(self): def impl_get_group_type(self):
return self._group_type return self._group_type
def _valid_consistency(self, opt, value, context, index): def _valid_consistency(self, opt, value, context=None, index=None):
consistencies = self._consistencies.get(opt) consistencies = self._consistencies.get(opt)
if consistencies is not None: if consistencies is not None:
for consistency in consistencies: for consistency in consistencies:
func, opts = consistency func, opts = consistency
ret = getattr(opts[0], func)(opt, value, context, index, opts) #ret = getattr(opts[0], func)(opt, value, context, index, opts)
ret = opts[0]._launch_consistency(func, opt, value, context,
index, opts)
if ret is False: if ret is False:
return False return False
return True return True
@ -784,7 +778,7 @@ def validate_requires_arg(requires, name):
if not isinstance(req[0], Option): if not isinstance(req[0], Option):
raise ValueError(_('malformed requirements first argument ' raise ValueError(_('malformed requirements first argument '
'must be an option in option {0}').format(name)) 'must be an option in option {0}').format(name))
if req[0].optimpl_is_multi(): if req[0].impl_is_multi():
raise ValueError(_('malformed requirements option {0} ' raise ValueError(_('malformed requirements option {0} '
'should not be a multi').format(name)) 'should not be a multi').format(name))
if not req[0]._validate(req[1]): if not req[0]._validate(req[1]):

View File

@ -21,6 +21,7 @@
# the whole pypy projet is under MIT licence # the whole pypy projet is under MIT licence
# ____________________________________________________________ # ____________________________________________________________
from time import time from time import time
from copy import copy
from tiramisu.error import RequirementRecursionError, PropertiesOptionError from tiramisu.error import RequirementRecursionError, PropertiesOptionError
from tiramisu.i18n import _ from tiramisu.i18n import _
@ -152,22 +153,21 @@ class Property(object):
self._properties = prop self._properties = prop
def append(self, propname): def append(self, propname):
if not propname in self._properties: self._properties.add(propname)
self._properties.append(propname) self._setting._set_properties(self._properties, self._opt)
self._setting._set_properties(self._properties, self._opt)
self._setting.context.cfgimpl_reset_cache() self._setting.context.cfgimpl_reset_cache()
def remove(self, propname): def remove(self, propname):
if propname in self._properties: if propname in self._properties:
self._properties.remove(propname) self._properties.remove(propname)
self._setting._set_properties(self._properties, self._opt) self._setting._set_properties(self._properties, self._opt)
self._setting.context.cfgimpl_reset_cache() self._setting.context.cfgimpl_reset_cache()
def __contains__(self, propname): def __contains__(self, propname):
return propname in self._properties return propname in self._properties
def __repr__(self): def __repr__(self):
return str(self._properties) return str(list(self._properties))
#____________________________________________________________ #____________________________________________________________
@ -178,7 +178,7 @@ class Setting(object):
def __init__(self, context): def __init__(self, context):
# properties attribute: the name of a property enables this property # properties attribute: the name of a property enables this property
# key is None for global properties # key is None for global properties
self._properties = {None: ['expire']} self._properties = {None: set(('expire',))}
# permissive properties # permissive properties
self._permissives = {} self._permissives = {}
# generic owner # generic owner
@ -192,7 +192,7 @@ class Setting(object):
return propname in self._get_properties() return propname in self._get_properties()
def __repr__(self): def __repr__(self):
return str(self._get_properties()) return str(list(self._get_properties()))
def __getitem__(self, opt): def __getitem__(self, opt):
return Property(self, self._get_properties(opt), opt) return Property(self, self._get_properties(opt), opt)
@ -202,7 +202,7 @@ class Setting(object):
def _get_properties(self, opt=None, is_apply_req=True): def _get_properties(self, opt=None, is_apply_req=True):
if opt is None: if opt is None:
props = self._properties.get(opt, []) props = self._properties.get(opt, set())
else: else:
exp = None exp = None
if opt in self._cache: if opt in self._cache:
@ -212,8 +212,7 @@ class Setting(object):
return props return props
if is_apply_req: if is_apply_req:
apply_requires(opt, self.context) apply_requires(opt, self.context)
default = list(opt._properties) props = self._properties.get(opt, opt._properties)
props = self._properties.get(opt, default)
self._set_cache(opt, props, exp) self._set_cache(opt, props, exp)
return props return props
@ -243,24 +242,23 @@ class Setting(object):
value=None, force_permissive=False, value=None, force_permissive=False,
force_properties=None): force_properties=None):
#opt properties #opt properties
properties = set(self._get_properties(opt_or_descr)) properties = copy(self._get_properties(opt_or_descr))
#remove opt permissive #remove opt permissive
properties -= frozenset(self._get_permissive(opt_or_descr)) properties -= self._get_permissive(opt_or_descr)
#remove global permissive if need #remove global permissive if need
self_properties = self._get_properties() self_properties = copy(self._get_properties())
if force_permissive is True or 'permissive' in self_properties: if force_permissive is True or 'permissive' in self_properties:
properties -= frozenset(self._get_permissive()) properties -= self._get_permissive()
#global properties #global properties
set_properties = set(self_properties)
if force_properties is not None: if force_properties is not None:
set_properties.update(frozenset(force_properties)) self_properties.update(force_properties)
#calc properties #calc properties
properties &= set_properties properties &= self_properties
#mandatory and frozen are special properties #mandatory and frozen are special properties
if is_descr: if is_descr:
properties -= frozenset(['mandatory', 'frozen']) properties -= frozenset(('mandatory', 'frozen'))
else: else:
if 'mandatory' in properties and \ if 'mandatory' in properties and \
not self.context.cfgimpl_get_values()._is_empty(opt_or_descr, not self.context.cfgimpl_get_values()._is_empty(opt_or_descr,
@ -281,12 +279,12 @@ class Setting(object):
list(properties)) list(properties))
def _get_permissive(self, opt=None): def _get_permissive(self, opt=None):
return self._permissives.get(opt, []) return self._permissives.get(opt, frozenset())
def set_permissive(self, permissive, opt=None): def set_permissive(self, permissive, opt=None):
if not isinstance(permissive, tuple): if not isinstance(permissive, tuple):
raise TypeError(_('permissive must be a tuple')) raise TypeError(_('permissive must be a tuple'))
self._permissives[opt] = permissive self._permissives[opt] = frozenset(permissive)
#____________________________________________________________ #____________________________________________________________
def setowner(self, owner): def setowner(self, owner):
@ -347,7 +345,7 @@ def apply_requires(opt, config):
setting = Property(settings, settings._get_properties(opt, False), opt) setting = Property(settings, settings._get_properties(opt, False), opt)
trigger_actions = build_actions(opt._requires) trigger_actions = build_actions(opt._requires)
descr = config.cfgimpl_get_context().cfgimpl_get_description() descr = config.cfgimpl_get_context().cfgimpl_get_description()
optpath = descr.optimpl_get_path_by_opt(opt) optpath = descr.impl_get_path_by_opt(opt)
for requires in trigger_actions.values(): for requires in trigger_actions.values():
matches = False matches = False
for require in requires: for require in requires:
@ -356,7 +354,7 @@ def apply_requires(opt, config):
inverse = False inverse = False
elif len(require) == 4: elif len(require) == 4:
option, expected, action, inverse = require option, expected, action, inverse = require
path = descr.optimpl_get_path_by_opt(option) path = descr.impl_get_path_by_opt(option)
if path == optpath or path.startswith(optpath + '.'): if path == optpath or path.startswith(optpath + '.'):
raise RequirementRecursionError(_("malformed requirements " raise RequirementRecursionError(_("malformed requirements "
"imbrication detected for option: '{0}' " "imbrication detected for option: '{0}' "

View File

@ -44,14 +44,14 @@ class Values(object):
if meta is not None: if meta is not None:
return meta.cfgimpl_get_values()[opt] return meta.cfgimpl_get_values()[opt]
else: else:
return opt.optimpl_getdefault() return opt.impl_getdefault()
def _get_value(self, opt): def _get_value(self, opt):
"return value or default value if not set" "return value or default value if not set"
#if no value #if no value
if opt not in self._values: if opt not in self._values:
value = self._get_default(opt) value = self._get_default(opt)
if opt.optimpl_is_multi(): if opt.impl_is_multi():
value = Multi(value, self.context, opt) value = Multi(value, self.context, opt)
else: else:
#if value #if value
@ -63,15 +63,17 @@ class Values(object):
def _reset(self, opt): def _reset(self, opt):
if opt in self._values: if opt in self._values:
setting = self.context.cfgimpl_get_settings()
opt.impl_validate(opt.impl_getdefault(), self.context, 'validator' in setting)
self.context.cfgimpl_reset_cache() self.context.cfgimpl_reset_cache()
del(self._values[opt]) del(self._values[opt])
def _is_empty(self, opt, value): def _is_empty(self, opt, value):
"convenience method to know if an option is empty" "convenience method to know if an option is empty"
empty = opt._empty empty = opt._empty
if (not opt.optimpl_is_multi() and (value is None or value == empty)) or \ if (not opt.impl_is_multi() and (value is None or value == empty)) or \
(opt.optimpl_is_multi() and (value == [] or (opt.impl_is_multi() and (value == [] or
None in value or empty in value)): None in value or empty in value)):
return True return True
return False return False
@ -97,7 +99,8 @@ class Values(object):
if exp < created: if exp < created:
return value return value
val = self._getitem(opt, validate, force_permissive, force_properties) val = self._getitem(opt, validate, force_permissive, force_properties)
self._set_cache(opt, val) if validate:
self._set_cache(opt, val)
return val return val
def _getitem(self, opt, validate, force_permissive, force_properties): def _getitem(self, opt, validate, force_permissive, force_properties):
@ -105,7 +108,7 @@ class Values(object):
setting = self.context.cfgimpl_get_settings() setting = self.context.cfgimpl_get_settings()
value = self._get_value(opt) value = self._get_value(opt)
is_frozen = 'frozen' in setting[opt] is_frozen = 'frozen' in setting[opt]
if opt.optimpl_has_callback(): if opt.impl_has_callback():
#if value is set and : #if value is set and :
# - not frozen # - not frozen
# - frozen and not force_default_on_freeze # - frozen and not force_default_on_freeze
@ -115,18 +118,17 @@ class Values(object):
pass pass
else: else:
value = self._getcallback_value(opt) value = self._getcallback_value(opt)
if opt.optimpl_is_multi(): if opt.impl_is_multi():
value = Multi(value, self.context, opt) value = Multi(value, self.context, opt)
#suppress value if already set #suppress value if already set
self._reset(opt) self._reset(opt)
# frozen and force default # frozen and force default
elif is_frozen and 'force_default_on_freeze' in setting[opt]: elif is_frozen and 'force_default_on_freeze' in setting[opt]:
value = self._get_default(opt) value = self._get_default(opt)
if opt.optimpl_is_multi(): if opt.impl_is_multi():
value = Multi(value, self.context, opt) value = Multi(value, self.context, opt)
if validate and not opt.optimpl_validate(value, self.context, 'validator' in setting): if validate:
raise ValueError(_('invalid calculated value returned' opt.impl_validate(value, self.context, 'validator' in setting)
' for option {0}: {1}').format(opt._name, value))
if self.is_default_owner(opt) and \ if self.is_default_owner(opt) and \
'force_store_value' in setting[opt]: 'force_store_value' in setting[opt]:
self.setitem(opt, value, is_write=False) self.setitem(opt, value, is_write=False)
@ -142,11 +144,9 @@ class Values(object):
#is_write is, for example, used with "force_store_value" #is_write is, for example, used with "force_store_value"
#user didn't change value, so not write #user didn't change value, so not write
#valid opt #valid opt
if not opt.optimpl_validate(value, self.context, opt.impl_validate(value, self.context,
'validator' in self.context.cfgimpl_get_settings()): 'validator' in self.context.cfgimpl_get_settings())
raise ValueError(_('invalid value {}' if opt.impl_is_multi() and not isinstance(value, Multi):
' for option {}').format(value, opt._name))
if opt.optimpl_is_multi() and not isinstance(value, Multi):
value = Multi(value, self.context, opt) value = Multi(value, self.context, opt)
self._setvalue(opt, value, force_permissive=force_permissive, self._setvalue(opt, value, force_permissive=force_permissive,
is_write=is_write) is_write=is_write)
@ -219,16 +219,16 @@ class Multi(list):
self.context = context self.context = context
if not isinstance(value, list): if not isinstance(value, list):
value = [value] value = [value]
if self.opt.optimpl_get_multitype() == multitypes.slave: if self.opt.impl_get_multitype() == multitypes.slave:
value = self._valid_slave(value) value = self._valid_slave(value)
elif self.opt.optimpl_get_multitype() == multitypes.master: elif self.opt.impl_get_multitype() == multitypes.master:
self._valid_master(value) self._valid_master(value)
super(Multi, self).__init__(value) super(Multi, self).__init__(value)
def _valid_slave(self, value): def _valid_slave(self, value):
#if slave, had values until master's one #if slave, had values until master's one
masterp = self.context.cfgimpl_get_description().optimpl_get_path_by_opt( masterp = self.context.cfgimpl_get_description().impl_get_path_by_opt(
self.opt.optimpl_get_master_slaves()) self.opt.impl_get_master_slaves())
mastervalue = getattr(self.context, masterp) mastervalue = getattr(self.context, masterp)
masterlen = len(mastervalue) masterlen = len(mastervalue)
if len(value) > masterlen or (len(value) < masterlen and if len(value) > masterlen or (len(value) < masterlen and
@ -238,7 +238,7 @@ class Multi(list):
self.opt._name, masterp)) self.opt._name, masterp))
elif len(value) < masterlen: elif len(value) < masterlen:
for num in range(0, masterlen - len(value)): for num in range(0, masterlen - len(value)):
value.append(self.opt.optimpl_getdefault_multi()) value.append(self.opt.impl_getdefault_multi())
#else: same len so do nothing #else: same len so do nothing
return value return value
@ -255,7 +255,7 @@ class Multi(list):
self.opt._name, slave._name)) self.opt._name, slave._name))
elif len(value_slave) < masterlen: elif len(value_slave) < masterlen:
for num in range(0, masterlen - len(value_slave)): for num in range(0, masterlen - len(value_slave)):
value_slave.append(slave.optimpl_getdefault_multi(), force=True) value_slave.append(slave.impl_getdefault_multi(), force=True)
def __setitem__(self, key, value): def __setitem__(self, key, value):
self._validate(value) self._validate(value)
@ -268,14 +268,14 @@ class Multi(list):
only if the option is a master only if the option is a master
""" """
if not force: if not force:
if self.opt.optimpl_get_multitype() == multitypes.slave: if self.opt.impl_get_multitype() == multitypes.slave:
raise SlaveError(_("cannot append a value on a multi option {0}" raise SlaveError(_("cannot append a value on a multi option {0}"
" which is a slave").format(self.opt._name)) " which is a slave").format(self.opt._name))
elif self.opt.optimpl_get_multitype() == multitypes.master: elif self.opt.impl_get_multitype() == multitypes.master:
for slave in self.opt.optimpl_get_master_slaves(): for slave in self.opt.impl_get_master_slaves():
values = self.context.cfgimpl_get_values() values = self.context.cfgimpl_get_values()
if not values.is_default_owner(slave): if not values.is_default_owner(slave):
values[slave].append(slave.optimpl_getdefault_multi(), values[slave].append(slave.impl_getdefault_multi(),
force=True) force=True)
self._validate(value) self._validate(value)
#assume not checking mandatory property #assume not checking mandatory property
@ -296,11 +296,11 @@ class Multi(list):
:return: the requested element :return: the requested element
""" """
if not force: if not force:
if self.opt.optimpl_get_multitype() == multitypes.slave: if self.opt.impl_get_multitype() == multitypes.slave:
raise SlaveError(_("cannot pop a value on a multi option {0}" raise SlaveError(_("cannot pop a value on a multi option {0}"
" which is a slave").format(self.opt._name)) " which is a slave").format(self.opt._name))
elif self.opt.optimpl_get_multitype() == multitypes.master: elif self.opt.impl_get_multitype() == multitypes.master:
for slave in self.opt.optimpl_get_master_slaves(): for slave in self.opt.impl_get_master_slaves():
self.context.cfgimpl_get_values()[slave].pop(key, force=True) self.context.cfgimpl_get_values()[slave].pop(key, force=True)
self.context.cfgimpl_get_values()._setvalue(self.opt, self) self.context.cfgimpl_get_values()._setvalue(self.opt, self)
return super(Multi, self).pop(key) return super(Multi, self).pop(key)