Merge branch 'master' into metaconfig

This commit is contained in:
Emmanuel Garette 2014-02-02 18:21:22 +01:00
commit f8faec408f
25 changed files with 1453 additions and 670 deletions

View file

@ -10,8 +10,6 @@ Tiramisu is made of almost three main objects :
- :class:`tiramisu.option.OptionDescription` is the shema, the option's structure
- :class:`tiramisu.config.Config` which is the whole configuration entry point
.. image:: config.png
Accessing the `Option`'s
-------------------------
@ -47,9 +45,13 @@ object is returned, and if no `Option` has been declared in the
The `Option` objects (in this case the :class:`~tiramisu.option.BoolOption`),
are organized into a tree into nested
:class:`~tiramisu.option.OptionDescription` objects. Every option has a name,
as does every option group. The parts of the full name of the option are
separated by dots: e.g. ``cfg.optgroup.optname``.
:class:`~tiramisu.option.OptionDescription` objects.
.. image:: config.png
Every option has a name, as does every option group. The parts
of the full name of the option are separated by dots: e.g.
``cfg.optgroup.optname``.
Let's make the protocol of accessing a `Config`'s attribute explicit
(because explicit is better than implicit):
@ -363,6 +365,10 @@ read/write or read only mode::
>>> print c.od1.var3
value
Many properties can be defined at the same time on an option::
>>> c.cfgimpl_get_settings().extend(['unknown1', 'unknown2'])
Properties can also be defined on an option group (that is, on an
:term:`option description`) let's hide a group and try to access to it::

View file

@ -9,7 +9,7 @@ from py.test import raises
from tiramisu.config import Config
from tiramisu.option import IntOption, FloatOption, StrOption, ChoiceOption, \
BoolOption, UnicodeOption, OptionDescription
from tiramisu.error import ConflictError
from tiramisu.error import ConflictError, ConfigError
def make_description():
@ -131,8 +131,10 @@ def test_cfgimpl_get_home_by_path():
config.bool = False
assert config.cfgimpl_get_home_by_path('gc.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=True) == ['gc', 'gc.name', 'gc.dummy', 'gc.float', 'bool', 'objspace', 'wantref', 'str', 'wantframework', 'int', 'boolop']
def test_not_valid_properties():
raises(TypeError, "stroption = StrOption('str', 'Test string option', default='abc', properties=['mandatory',])")
def test_information_config():
@ -142,6 +144,7 @@ def test_information_config():
config.impl_set_information('info', string)
assert config.impl_get_information('info') == string
raises(ValueError, "config.impl_get_information('noinfo')")
assert config.impl_get_information('noinfo', 'default') == 'default'
def test_config_impl_get_path_by_opt():
@ -149,8 +152,10 @@ def test_config_impl_get_path_by_opt():
config = Config(descr)
dummy = config.unwrap_from_path('gc.dummy')
boo = config.unwrap_from_path('bool')
unknown = IntOption('test', '')
assert config.cfgimpl_get_description().impl_get_path_by_opt(boo) == 'bool'
assert config.cfgimpl_get_description().impl_get_path_by_opt(dummy) == 'gc.dummy'
raises(AttributeError, "config.cfgimpl_get_description().impl_get_path_by_opt(unknown)")
def test_config_impl_get_opt_by_path():
@ -160,6 +165,7 @@ def test_config_impl_get_opt_by_path():
boo = config.unwrap_from_path('bool')
assert config.cfgimpl_get_description().impl_get_opt_by_path('bool') == boo
assert config.cfgimpl_get_description().impl_get_opt_by_path('gc.dummy') == dummy
raises(AttributeError, "config.cfgimpl_get_description().impl_get_opt_by_path('gc.unknown')")
def test_information_display():
@ -231,8 +237,60 @@ def test_duplicated_option():
#in different OptionDescription
raises(ConflictError, "config = Config(root)")
def test_cannot_assign_value_to_option_description():
descr = make_description()
cfg = Config(descr)
raises(TypeError, "cfg.gc = 3")
def test_config_multi():
i1 = IntOption('test1', '', multi=True)
i2 = IntOption('test2', '', multi=True, default_multi=1)
i3 = IntOption('test3', '', default=[2], multi=True, default_multi=1)
od = OptionDescription('test', '', [i1, i2, i3])
config = Config(od)
assert config.test1 == []
assert config.test2 == []
config.test2.append()
assert config.test2 == [1]
assert config.test3 == [2]
config.test3.append()
assert config.test3 == [2, 1]
def test_no_validation():
i1 = IntOption('test1', '')
od = OptionDescription('test', '', [i1])
c = Config(od)
setting = c.cfgimpl_get_settings()
c.test1 = 1
raises(ValueError, 'c.test1 = "yes"')
assert c.test1 == 1
setting.remove('validator')
c.test1 = "yes"
assert c.test1 == "yes"
setting.append('validator')
raises(ValueError, 'c.test1')
del(c.test1)
assert c.test1 is None
def test_delete_config_with_subconfig():
test = IntOption('test', '')
multi = IntOption('multi', '', multi=True)
od = OptionDescription('od', '', [test, multi])
odroot = OptionDescription('odroot', '', [od])
c = Config(odroot)
sub = c.od
val = c.cfgimpl_get_values()
setting = c.cfgimpl_get_settings()
val[test]
val[multi]
setting[test]
sub.make_dict()
del(c)
raises(ConfigError, 'val[test]')
raises(ConfigError, 'val[multi]')
raises(ConfigError, 'setting[test]')
raises(ConfigError, 'sub.make_dict()')

View file

@ -4,26 +4,31 @@ from py.test import raises
from tiramisu.config import Config
from tiramisu.option import IntOption, FloatOption, StrOption, ChoiceOption, \
BoolOption, OptionDescription
BoolOption, FilenameOption, OptionDescription
def make_description():
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
gcdummy = BoolOption('dummy', 'dummy', default=False)
prop = BoolOption('prop', '', properties=('disabled',))
prop2 = BoolOption('prop', '', properties=('hidden',))
objspaceoption = ChoiceOption('objspace', 'Object space',
('std', 'thunk'), 'std')
booloption = BoolOption('bool', 'Test boolean option', default=True)
booloption2 = BoolOption('bool', 'Test boolean option', default=False)
intoption = IntOption('int', 'Test int option', default=0)
floatoption2 = FloatOption('float', 'Test float option', default=2.3)
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', 'Tests', default=False)
wantframework_option = BoolOption('wantframework', 'Test', default=False)
gcgroup = OptionDescription('gc', '', [gcoption, gcdummy, floatoption])
gcgroup2 = OptionDescription('gc2', '', [booloption2, prop])
gcgroup = OptionDescription('gc', '', [gcgroup2, gcoption, gcdummy, floatoption, prop2])
descr = OptionDescription('tiramisu', '', [gcgroup, booloption, objspaceoption,
wantref_option, stroption,
wantframework_option,
intoption, boolop])
intoption, boolop, floatoption2])
return descr
@ -100,20 +105,40 @@ def test_find_in_config():
"finds option in config"
descr = make_description()
conf = Config(descr)
conf.read_only()
assert conf.find(byname='dummy') == [conf.unwrap_from_path('gc.dummy')]
assert conf.find(byname='float') == [conf.unwrap_from_path('gc.float'), conf.unwrap_from_path('float')]
assert conf.find_first(byname='bool') == conf.unwrap_from_path('gc.gc2.bool')
assert conf.find_first(byname='bool', byvalue=True) == conf.unwrap_from_path('bool')
assert conf.find_first(byname='dummy') == conf.unwrap_from_path('gc.dummy')
assert conf.find_first(byname='float') == conf.unwrap_from_path('gc.float')
assert conf.find(bytype=ChoiceOption) == [conf.unwrap_from_path('gc.name'), conf.unwrap_from_path('objspace')]
assert conf.find_first(bytype=ChoiceOption) == conf.unwrap_from_path('gc.name')
assert conf.find(byvalue='ref') == [conf.unwrap_from_path('gc.name')]
assert conf.find_first(byvalue='ref') == conf.unwrap_from_path('gc.name')
assert conf.find(byname='prop') == [conf.unwrap_from_path('gc.prop')]
conf.read_write()
raises(AttributeError, "assert conf.find(byname='prop')")
assert conf.find(byname='prop', check_properties=False) == [conf.unwrap_from_path('gc.gc2.prop'), conf.unwrap_from_path('gc.prop')]
#assert conf.find_first(byname='prop') == conf.unwrap_from_path('gc.prop')
# combinaison of filters
assert conf.find(bytype=BoolOption, byname='dummy') == [conf.unwrap_from_path('gc.dummy')]
assert conf.find_first(bytype=BoolOption, byname='dummy') == conf.unwrap_from_path('gc.dummy')
assert conf.find(byvalue=False, byname='dummy') == [conf.unwrap_from_path('gc.dummy')]
assert conf.find_first(byvalue=False, byname='dummy') == conf.unwrap_from_path('gc.dummy')
## byattrs
#assert conf.find_first(byattrs= dict(default=2.3)) == conf.unwrap_from_path('gc.float')
#assert conf.find_first(byvalue=False, byname='dummy', byattrs=dict(default=False)) == conf.unwrap_from_path('gc.dummy')
#subconfig
assert conf.gc.find(byname='dummy') == [conf.unwrap_from_path('gc.dummy')]
assert conf.gc.find(byname='float') == [conf.unwrap_from_path('gc.float')]
assert conf.gc.find(byname='bool') == [conf.unwrap_from_path('gc.gc2.bool')]
assert conf.gc.find_first(byname='bool', byvalue=False) == conf.unwrap_from_path('gc.gc2.bool')
raises(AttributeError, "assert conf.gc.find_first(byname='bool', byvalue=True)")
raises(AttributeError, "conf.gc.find(byname='wantref').first()")
assert conf.gc.find(byname='prop', check_properties=False) == [conf.unwrap_from_path('gc.gc2.prop'), conf.unwrap_from_path('gc.prop')]
conf.read_only()
assert conf.gc.find(byname='prop') == [conf.unwrap_from_path('gc.prop')]
# not OptionDescription
raises(AttributeError, "conf.find_first(byname='gc')")
raises(AttributeError, "conf.gc.find_first(byname='gc2')")
def test_find_multi():
@ -137,3 +162,18 @@ def test_does_not_find_in_config():
descr = make_description()
conf = Config(descr)
raises(AttributeError, "conf.find(byname='IDontExist')")
def test_filename():
a = FilenameOption('a', '')
o = OptionDescription('o', '', [a])
c = Config(o)
c.a = u'/'
c.a = u'/tmp'
c.a = u'/tmp/'
c.a = u'/tmp/text.txt'
c.a = u'tmp'
c.a = u'tmp/'
c.a = u'tmp/text.txt'
raises(ValueError, "c.a = u'/tmp/with space.txt'")
raises(ValueError, "c.a = u'/tmp/with$.txt'")

View file

@ -2,23 +2,28 @@ import autopath
from py.test import raises
from tiramisu.config import Config
from tiramisu.option import DomainnameOption, OptionDescription
from tiramisu.option import DomainnameOption, EmailOption, URLOption, OptionDescription
def test_domainname():
d = DomainnameOption('d', '')
e = DomainnameOption('e', '', "toto.com")
od = OptionDescription('a', '', [d, e])
f = DomainnameOption('f', '', allow_without_dot=True)
od = OptionDescription('a', '', [d, f])
c = Config(od)
c.read_write()
c.d = 'toto.com'
raises(ValueError, "c.d = 'toto'")
c.d = 'toto3.com'
c.d = 'toto3.3la'
raises(ValueError, "c.d = 'toto3.3la'")
raises(ValueError, "c.d = '3toto.com'")
c.d = 'toto.co3'
raises(ValueError, "c.d = 'toto.co3'")
raises(ValueError, "c.d = 'toto_super.com'")
c.d = 'toto-.com'
raises(ValueError, "c.d = 'toto..com'")
#
c.f = 'toto.com'
c.f = 'toto'
def test_domainname_netbios():
@ -41,3 +46,33 @@ def test_domainname_hostname():
raises(ValueError, "c.d = 'toto.com'")
c.d = 'toto'
c.d = 'domainnametoolong'
def test_email():
e = EmailOption('e', '')
od = OptionDescription('a', '', [e])
c = Config(od)
c.read_write()
c.e = 'root@foo.com'
raises(ValueError, "c.e = 'root'")
raises(ValueError, "c.e = 'root@domain'")
def test_url():
u = URLOption('u', '')
od = OptionDescription('a', '', [u])
c = Config(od)
c.read_write()
c.u = 'http://foo.com'
c.u = 'https://foo.com'
c.u = 'https://foo.com/'
raises(ValueError, "c.u = 'ftp://foo.com'")
raises(ValueError, "c.u = 'foo.com'")
raises(ValueError, "c.u = ':/foo.com'")
raises(ValueError, "c.u = 'foo.com/http://'")
c.u = 'https://foo.com/index.html'
c.u = 'https://foo.com/index.html?var=value&var2=val2'
raises(ValueError, "c.u = 'https://foo.com/index\\n.html'")
c.u = 'https://foo.com:8443'
c.u = 'https://foo.com:8443/'
c.u = 'https://foo.com:8443/index.html'

View file

@ -21,6 +21,11 @@ def test_ip():
c.b = '0.0.0.0'
raises(ValueError, "c.b = '255.255.255.0'")
raises(ValueError, "IPOption('a', 'ip', default='192.000.023.01')")
d = IPOption('a', 'ip', default='192.0.23.1')
od = OptionDescription('od', '', [d])
c = Config(od)
raises(ValueError, "c.a = '192.000.023.01'")
def test_ip_default():
a = IPOption('a', '', '88.88.88.88')

21
test/test_multi.py Normal file
View file

@ -0,0 +1,21 @@
# coding: utf-8
import autopath
from tiramisu.value import Multi
from tiramisu.option import IntOption, OptionDescription
from tiramisu.config import Config
from tiramisu.error import ConfigError
import weakref
from py.test import raises
def test_multi():
i = IntOption('int', '', multi=True)
o = OptionDescription('od', '', [i])
c = Config(o)
multi = Multi([1,2,3], weakref.ref(c), i, 'int')
raises(ValueError, "Multi([1,2,3], c, i, 'int')")
raises(ValueError, "Multi(multi, weakref.ref(c), i, 'int')")
assert c is multi._getcontext()
del(c)
raises(ConfigError, "multi._getcontext()")

View file

@ -2,8 +2,13 @@
and to compare them
"""
import autopath
from py.test import raises
from tiramisu.option import BoolOption, IntOption
from tiramisu.option import IntOption, OptionDescription
def a_func():
return None
#def test_option_comparison():
@ -36,3 +41,60 @@ from tiramisu.option import BoolOption, IntOption
# assert dummy1 != dummy5
# assert dummy1 == dummy6
# assert dummy1 != dummy7
def test_option_valid_name():
IntOption('test', '')
raises(ValueError, 'IntOption(1, "")')
raises(ValueError, 'IntOption("impl_test", "")')
raises(ValueError, 'IntOption("_test", "")')
raises(ValueError, 'IntOption("unwrap_from_path", "")')
def test_option_with_callback():
#no default value with callback
raises(ValueError, "IntOption('test', '', default=1, callback=a_func)")
def test_option_get_information():
description = "it's ok"
string = 'some informations'
i = IntOption('test', description)
i.impl_set_information('info', string)
assert i.impl_get_information('info') == string
raises(ValueError, "i.impl_get_information('noinfo')")
assert i.impl_get_information('noinfo', 'default') == 'default'
assert i.impl_get_information('doc') == description
assert i.impl_getdoc() == description
def test_optiondescription_get_information():
description = "it's ok"
string = 'some informations'
o = OptionDescription('test', description, [])
o.impl_set_information('info', string)
assert o.impl_get_information('info') == string
raises(ValueError, "o.impl_get_information('noinfo')")
assert o.impl_get_information('noinfo', 'default') == 'default'
assert o.impl_get_information('doc') == description
assert o.impl_getdoc() == description
def test_option_multi():
IntOption('test', '', multi=True)
IntOption('test', '', multi=True, default_multi=1)
IntOption('test', '', default=[1], multi=True, default_multi=1)
#add default_multi to not multi's option
raises(ValueError, "IntOption('test', '', default_multi=1)")
#unvalid default_multi
raises(ValueError, "IntOption('test', '', multi=True, default_multi='yes')")
#not default_multi with callback
raises(ValueError, "IntOption('test', '', multi=True, default_multi=1, callback=a_func)")
def test_option_is_multi_by_default():
assert IntOption('test', '').impl_is_empty_by_default() is True
assert IntOption('test', '', 1).impl_is_empty_by_default() is False
assert IntOption('test', '', multi=True).impl_is_empty_by_default() is True
assert IntOption('test', '', [1], multi=True).impl_is_empty_by_default() is False
assert IntOption('test', '', multi=True, default_multi=1).impl_is_empty_by_default() is True

View file

@ -21,7 +21,13 @@ def return_list(value=None):
def return_list2(*args):
return list(args)
l = []
for arg in args:
if isinstance(arg, list):
l.extend(arg)
else:
l.append(arg)
return l
def return_value(value=None):
@ -34,6 +40,10 @@ def return_value2(*args, **kwargs):
return value
def return_calc(i, j, k):
return i + j + k
def make_description():
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
gcdummy = BoolOption('dummy', 'dummy', default=False)
@ -93,83 +103,6 @@ def test_identical_paths():
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=({'option': boolop, 'expected': True, 'action': 'hidden'},))
# second multi
wantframework_option = BoolOption('wantframework', 'Test requires',
default=False,
requires=({'option': boolop, 'expected': True, 'action': '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)
@ -310,6 +243,19 @@ def test_callback():
assert cfg.val1 == 'val'
def test_callback_params_without_callback():
raises(ValueError, "StrOption('val2', '', callback_params={'': ('yes',)})")
def test_callback_invalid():
raises(ValueError, 'val1 = StrOption("val1", "", callback="string")')
raises(ValueError, 'val1 = StrOption("val1", "", callback=return_val, callback_params="string")')
val1 = StrOption('val1', "", 'val')
raises(ValueError, "StrOption('val2', '', callback=return_value, callback_params={'': 'string'})")
raises(ValueError, "StrOption('val4', '', callback=return_value, callback_params={'value': (('string', False),)})")
raises(ValueError, "StrOption('val4', '', callback=return_value, callback_params={'value': ((val1, 'string'),)})")
def test_callback_value():
val1 = StrOption('val1', "", 'val')
val2 = StrOption('val2', "", callback=return_value, callback_params={'': ((val1, False),)})
@ -421,12 +367,15 @@ def test_callback_multi_value():
cfg.val1.append('new-val2')
assert cfg.val1 == ['new-val', 'new-val2']
assert cfg.val2 == ['new-val', 'new-val2']
assert cfg.val4 == ['new-val', 'yes', 'new-val2', 'yes']
assert cfg.val4 == ['new-val', 'new-val2', 'yes']
del(cfg.val1)
assert cfg.val1 == ['val']
assert cfg.val2 == ['val']
assert cfg.val3 == ['yes']
assert cfg.val4 == ['val', 'yes']
cfg.val2.append('new')
assert cfg.val1 == ['val']
assert cfg.val2 == ['val', 'new']
def test_callback_multi_list():
@ -443,6 +392,14 @@ def test_callback_multi_list():
assert cfg.val1 == ['val', 'val']
def test_callback_multi_list_extend():
val1 = StrOption('val1', "", callback=return_list2, callback_params={'': (['1', '2', '3'], ['4', '5'])}, multi=True)
maconfig = OptionDescription('rootconfig', '', [val1])
cfg = Config(maconfig)
cfg.read_write()
assert cfg.val1 == ['1', '2', '3', '4', '5']
def test_callback_master_and_slaves_master():
val1 = StrOption('val1', "", multi=True, callback=return_val)
val2 = StrOption('val2', "", multi=True)
@ -452,7 +409,7 @@ def test_callback_master_and_slaves_master():
cfg = Config(maconfig)
cfg.read_write()
assert cfg.val1.val1 == ['val']
cfg.val1.val1.append(None)
cfg.val1.val1.append()
assert cfg.val1.val1 == ['val', 'val']
assert cfg.val1.val2 == [None, None]
@ -467,7 +424,7 @@ def test_callback_master_and_slaves_master_list():
cfg.read_write()
assert cfg.val1.val1 == ['val', 'val']
assert cfg.val1.val2 == [None, None]
cfg.val1.val1.append(None)
cfg.val1.val1.append()
assert cfg.val1.val1 == ['val', 'val', None]
assert cfg.val1.val2 == [None, None, None]
del(cfg.val1.val1)
@ -512,6 +469,66 @@ def test_callback_master_and_slaves_slave():
assert cfg.val1.val2 == ['val2', 'val2', 'val']
def test_callback_master_and_slaves_slave_cal():
val3 = StrOption('val3', "", multi=True)
val1 = StrOption('val1', "", multi=True, callback=return_value, callback_params={'': ((val3, False),)})
val2 = StrOption('val2', "", multi=True, callback=return_val)
interface1 = OptionDescription('val1', '', [val1, val2])
interface1.impl_set_group_type(groups.master)
maconfig = OptionDescription('rootconfig', '', [interface1, val3])
cfg = Config(maconfig)
cfg.read_write()
assert cfg.val3 == []
assert cfg.val1.val1 == []
assert cfg.val1.val2 == []
cfg.val1.val1 = ['val1']
cfg.val3 = ['val1']
assert cfg.val1.val1 == ['val1']
assert cfg.val1.val2 == ['val']
assert cfg.val1.val1 == ['val1']
assert cfg.val1.val2 == ['val']
del(cfg.val1.val1)
cfg.val1.val2 = ['val']
cfg.val3 = ['val1', 'val2']
assert cfg.val1.val2 == ['val', 'val']
assert cfg.val1.val1 == ['val1', 'val2']
cfg.val1.val2 = ['val1', 'val2']
cfg.val3.pop(1)
# cannot remove slave's value because master is calculated
# so raise
raises(SlaveError, "cfg.val1.val1")
raises(SlaveError, "cfg.val1.val2")
cfg.val3 = ['val1', 'val2', 'val3']
assert cfg.val1.val2 == ['val1', 'val2', 'val']
def test_callback_master_and_slaves_slave_cal2():
val3 = StrOption('val3', "", ['val', 'val'], multi=True)
val1 = StrOption('val1', "", multi=True, callback=return_value, callback_params={'': ((val3, False),)})
val2 = StrOption('val2', "", ['val2', 'val2'], multi=True)
interface1 = OptionDescription('val1', '', [val1, val2])
interface1.impl_set_group_type(groups.master)
maconfig = OptionDescription('rootconfig', '', [interface1, val3])
cfg = Config(maconfig)
cfg.read_write()
assert cfg.val3 == ['val', 'val']
assert cfg.val1.val1 == ['val', 'val']
assert cfg.val1.val2 == ['val2', 'val2']
cfg.val3.pop(1)
# # cannot remove slave's value because master is calculated
# # so raise
raises(SlaveError, "cfg.val1.val1")
raises(SlaveError, "cfg.val1.val2")
cfg.val3 = ['val', 'val']
assert cfg.val3 == ['val', 'val']
assert cfg.val1.val1 == ['val', 'val']
assert cfg.val1.val2 == ['val2', 'val2']
raises(SlaveError, "cfg.val1.val1 = ['val']")
assert cfg.val3 == ['val', 'val']
assert cfg.val1.val1 == ['val', 'val']
assert cfg.val1.val2 == ['val2', 'val2']
def test_callback_master_and_slaves_slave_list():
val1 = StrOption('val1', "", multi=True)
val2 = StrOption('val2', "", multi=True, callback=return_list)
@ -535,7 +552,8 @@ def test_callback_master_and_slaves_value():
val3 = StrOption('val3', "", multi=True, callback=return_value, callback_params={'': ('yes',)})
val4 = StrOption('val4', '', multi=True, default=['val10', 'val11'])
val5 = StrOption('val5', "", multi=True, callback=return_value, callback_params={'': ((val4, False),)})
interface1 = OptionDescription('val1', '', [val1, val2, val3, val5])
val6 = StrOption('val6', "", multi=True, callback=return_value, callback_params={'': ((val5, False),)})
interface1 = OptionDescription('val1', '', [val1, val2, val3, val5, val6])
interface1.impl_set_group_type(groups.master)
maconfig = OptionDescription('rootconfig', '', [interface1, val4])
cfg = Config(maconfig)
@ -544,30 +562,35 @@ def test_callback_master_and_slaves_value():
assert cfg.val1.val2 == []
assert cfg.val1.val3 == []
assert cfg.val1.val5 == []
assert cfg.val1.val6 == []
#
cfg.val1.val1 = ['val1']
assert cfg.val1.val1 == ['val1']
assert cfg.val1.val2 == ['val1']
assert cfg.val1.val3 == ['yes']
assert cfg.val1.val5 == ['val10']
assert cfg.val1.val6 == ['val10']
#
cfg.val1.val1.append('val2')
assert cfg.val1.val1 == ['val1', 'val2']
assert cfg.val1.val2 == ['val1', 'val2']
assert cfg.val1.val3 == ['yes', 'yes']
assert cfg.val1.val5 == ['val10', 'val11']
assert cfg.val1.val6 == ['val10', 'val11']
#
cfg.val1.val1 = ['val1', 'val2', 'val3']
assert cfg.val1.val1 == ['val1', 'val2', 'val3']
assert cfg.val1.val2 == ['val1', 'val2', 'val3']
assert cfg.val1.val3 == ['yes', 'yes', 'yes']
assert cfg.val1.val5 == ['val10', 'val11', None]
assert cfg.val1.val6 == ['val10', 'val11', None]
#
cfg.val1.val1.pop(2)
assert cfg.val1.val1 == ['val1', 'val2']
assert cfg.val1.val2 == ['val1', 'val2']
assert cfg.val1.val3 == ['yes', 'yes']
assert cfg.val1.val5 == ['val10', 'val11']
assert cfg.val1.val6 == ['val10', 'val11']
#
cfg.val1.val2 = ['val2', 'val2']
cfg.val1.val3 = ['val2', 'val2']
@ -575,11 +598,13 @@ def test_callback_master_and_slaves_value():
assert cfg.val1.val2 == ['val2', 'val2']
assert cfg.val1.val3 == ['val2', 'val2']
assert cfg.val1.val5 == ['val2', 'val2']
assert cfg.val1.val6 == ['val2', 'val2']
#
cfg.val1.val1.append('val3')
assert cfg.val1.val2 == ['val2', 'val2', 'val3']
assert cfg.val1.val3 == ['val2', 'val2', 'yes']
assert cfg.val1.val5 == ['val2', 'val2', None]
assert cfg.val1.val6 == ['val2', 'val2', None]
cfg.cfgimpl_get_settings().remove('cache')
cfg.val4 = ['val10', 'val11', 'val12']
#if value is already set, not updated !
@ -587,6 +612,69 @@ def test_callback_master_and_slaves_value():
cfg.val1.val1.append('val3')
cfg.val1.val1 = ['val1', 'val2', 'val3']
assert cfg.val1.val5 == ['val2', 'val2', 'val12']
assert cfg.val1.val6 == ['val2', 'val2', 'val12']
def test_callback_master():
val2 = StrOption('val2', "", multi=True, callback=return_value)
val1 = StrOption('val1', "", multi=True, callback=return_value, callback_params={'': ((val2, False),)})
interface1 = OptionDescription('val1', '', [val1, val2])
raises(ValueError, "interface1.impl_set_group_type(groups.master)")
def test_callback_master_and_other_master_slave():
val1 = StrOption('val1', "", multi=True)
val2 = StrOption('val2', "", multi=True)
val3 = StrOption('val3', "", multi=True)
val4 = StrOption('val4', '', multi=True, default=['val10', 'val11'])
val5 = StrOption('val5', "", multi=True, callback=return_value, callback_params={'': ((val1, False),)})
val6 = StrOption('val6', "", multi=True, callback=return_value, callback_params={'': ((val2, False),)})
interface1 = OptionDescription('val1', '', [val1, val2, val3])
interface1.impl_set_group_type(groups.master)
interface2 = OptionDescription('val4', '', [val4, val5, val6])
interface2.impl_set_group_type(groups.master)
maconfig = OptionDescription('rootconfig', '', [interface1, interface2])
cfg = Config(maconfig)
cfg.read_write()
assert cfg.val4.val4 == ['val10', 'val11']
assert cfg.val4.val5 == [None, None]
assert cfg.val4.val6 == [None, None]
cfg.val1.val1 = ['yes']
assert cfg.val4.val4 == ['val10', 'val11']
assert cfg.val4.val5 == ['yes', None]
assert cfg.val4.val6 == [None, None]
cfg.val1.val2 = ['no']
assert cfg.val4.val4 == ['val10', 'val11']
assert cfg.val4.val5 == ['yes', None]
assert cfg.val4.val6 == ['no', None]
cfg.val1.val1 = ['yes', 'yes', 'yes']
cfg.val1.val2 = ['no', 'no', 'no']
assert cfg.val4.val4 == ['val10', 'val11']
assert cfg.val4.val5 == ['yes', 'yes']
assert cfg.val4.val6 == ['no', 'no']
def test_callback_different_type():
val = IntOption('val', "", default=2)
val_ = IntOption('val_', "", default=3)
val1 = IntOption('val1', "", multi=True)
val2 = IntOption('val2', "", multi=True, callback=return_calc, callback_params={'': ((val, False), (val1, False)), 'k': ((val_, False),)})
interface1 = OptionDescription('val1', '', [val1, val2])
interface1.impl_set_group_type(groups.master)
maconfig = OptionDescription('rootconfig', '', [interface1, val, val_])
cfg = Config(maconfig)
cfg.read_write()
assert cfg.val1.val1 == []
assert cfg.val1.val2 == []
cfg.val1.val1 = [1]
assert cfg.val1.val1 == [1]
assert cfg.val1.val2 == [6]
cfg.val1.val1 = [1, 3]
assert cfg.val1.val1 == [1, 3]
assert cfg.val1.val2 == [6, 8]
cfg.val1.val1 = [1, 3, 5]
assert cfg.val1.val1 == [1, 3, 5]
assert cfg.val1.val2 == [6, 8, 10]
def test_callback_hidden():
@ -653,7 +741,7 @@ def test_callback_multi_list_params():
maconfig = OptionDescription('rootconfig', '', [val1, oval2])
cfg = Config(maconfig)
cfg.read_write()
assert cfg.val2.val2 == ['val', 'val', 'val', 'val']
assert cfg.val2.val2 == ['val', 'val']
def test_callback_multi_list_params_key():
@ -663,31 +751,4 @@ def test_callback_multi_list_params_key():
maconfig = OptionDescription('rootconfig', '', [val1, oval2])
cfg = Config(maconfig)
cfg.read_write()
assert cfg.val2.val2 == ['val', 'val', 'val', 'val']
def test_callback_multi_multi():
val1 = StrOption('val1', "", multi=True, default=['val1', 'val2', 'val3'])
val2 = StrOption('val2', "", multi=True, default=['val11', 'val12'])
val3 = StrOption('val3', "", default='val4')
val4 = StrOption('val4', "", multi=True, callback=return_list2, callback_params={'': ((val1, False), (val2, False))})
val5 = StrOption('val5', "", multi=True, callback=return_list2, callback_params={'': ((val1, False), (val3, False))})
val6 = StrOption('val6', "", multi=True, default=['val21', 'val22', 'val23'])
val7 = StrOption('val7', "", multi=True, callback=return_list2, callback_params={'': ((val1, False), (val6, False))})
raises(ValueError, "StrOption('val8', '', multi=True, callback=return_list2, callback_params={'value': ((val1, False), (val6, False))})")
maconfig = OptionDescription('rootconfig', '', [val1, val2, val3, val4, val5, val6, val7])
cfg = Config(maconfig)
cfg.read_write()
raises(ConfigError, "cfg.val4")
assert cfg.val5 == ['val1', 'val4', 'val2', 'val4', 'val3', 'val4']
assert cfg.val7 == ['val1', 'val21', 'val2', 'val22', 'val3', 'val23']
def test_multi_with_no_value():
#First option return [] (so without value)
val1 = StrOption('val1', "", ['val'], multi=True)
val2 = StrOption('val2', "", multi=True)
val3 = StrOption('val3', '', multi=True, callback=return_value, callback_params={'': ((val2, False),), 'value': ((val1, False),)})
od = OptionDescription('od', '', [val1, val2, val3])
c = Config(od)
raises(ConfigError, "c.val3")
assert cfg.val2.val2 == ['val', 'val']

View file

@ -8,6 +8,17 @@ from tiramisu.option import IPOption, NetworkOption, NetmaskOption, IntOption,\
from tiramisu.error import ConfigError
def test_consistency():
a = IntOption('a', '')
b = IntOption('b', '')
od = OptionDescription('od', '', [a, b])
a.impl_add_consistency('not_equal', b)
#consistency to itself
raises(ConfigError, "a.impl_add_consistency('not_equal', a)")
#consistency with string
raises(ConfigError, "a.impl_add_consistency('not_equal', 'a')")
def test_consistency_not_equal():
a = IntOption('a', '')
b = IntOption('b', '')

View file

@ -5,7 +5,7 @@ from tiramisu.setting import owners
from tiramisu.config import Config
from tiramisu.option import ChoiceOption, BoolOption, IntOption, FloatOption, \
StrOption, OptionDescription
from tiramisu.error import ConfigError
from tiramisu.error import ConfigError, ConstError
def make_description():
@ -52,6 +52,17 @@ def test_addowner():
assert cfg.getowner(gcdummy) == owners.gen_config
def test_addowner_multiple_time():
owners.addowner("testowner")
raises(ConstError, 'owners.addowner("testowner")')
def test_delete_owner():
owners.addowner('deleted')
raises(ConstError, 'del(owners.deleted)')
raises(ValueError, 'del(owners.deleted2)')
def test_owner_is_not_a_string():
gcdummy = BoolOption('dummy', 'dummy', default=False)
descr = OptionDescription('tiramisu', '', [gcdummy])

View file

@ -75,6 +75,16 @@ def test_group_is_hidden():
prop = err.proptype
assert 'hidden' in prop
def test_extend_properties():
descr = make_description()
config = Config(descr)
setting = config.cfgimpl_get_settings()
config.read_write()
gc = config.unwrap_from_path('gc')
config.unwrap_from_path('gc.dummy')
setting[gc].extend(['hidden', 'user_defined_property'])
assert 'hidden' in setting[gc]
assert 'user_defined_property' in setting[gc]
def test_group_is_hidden_multi():
descr = make_description()

View file

@ -6,6 +6,7 @@ from tiramisu.config import Config
from tiramisu.option import StrOption, OptionDescription
from tiramisu.setting import groups
from tiramisu.error import ValueWarning
from tiramisu.i18n import _
def return_true(value, param=None):
@ -87,7 +88,7 @@ def test_validator_warning():
cfg.opt2 = 'val'
assert len(w) == 1
assert w[0].message.opt == opt2
assert str(w[0].message) == 'invalid value val for option opt2: error'
assert str(w[0].message) == _('invalid value for option {0}: {1}').format('opt2', 'error')
#
with warnings.catch_warnings(record=True) as w:
cfg.opt3.append('val')
@ -97,7 +98,7 @@ def test_validator_warning():
cfg.opt3.append('val1')
assert len(w) == 1
assert w[0].message.opt == opt3
assert str(w[0].message) == 'invalid value val1 for option opt3: error'
assert str(w[0].message) == _('invalid value for option {0}: {1}').format('opt3', 'error')
raises(ValueError, "cfg.opt2 = 1")
#
with warnings.catch_warnings(record=True) as w:
@ -105,9 +106,9 @@ def test_validator_warning():
cfg.opt3.append('val')
assert len(w) == 2
assert w[0].message.opt == opt2
assert str(w[0].message) == 'invalid value val for option opt2: error'
assert str(w[0].message) == _('invalid value for option {0}: {1}').format('opt2', 'error')
assert w[1].message.opt == opt3
assert str(w[1].message) == 'invalid value val1 for option opt3: error'
assert str(w[1].message) == _('invalid value for option {0}: {1}').format('opt3', 'error')
def test_validator_warning_master_slave():
@ -127,29 +128,29 @@ def test_validator_warning_master_slave():
cfg.ip_admin_eth0.netmask_admin_eth0 = ['val1']
assert len(w) == 1
assert w[0].message.opt == netmask_admin_eth0
assert str(w[0].message) == 'invalid value val1 for option netmask_admin_eth0: error'
assert str(w[0].message) == _('invalid value for option {0}: {1}').format('netmask_admin_eth0', 'error')
#
with warnings.catch_warnings(record=True) as w:
cfg.ip_admin_eth0.ip_admin_eth0 = ['val']
assert len(w) == 1
assert w[0].message.opt == ip_admin_eth0
assert str(w[0].message) == 'invalid value val for option ip_admin_eth0: error'
assert str(w[0].message) == _('invalid value for option {0}: {1}').format('ip_admin_eth0', 'error')
#
with warnings.catch_warnings(record=True) as w:
cfg.ip_admin_eth0.ip_admin_eth0 = ['val', 'val1', 'val1']
assert len(w) == 1
assert w[0].message.opt == ip_admin_eth0
assert str(w[0].message) == 'invalid value val for option ip_admin_eth0: error'
assert str(w[0].message) == _('invalid value for option {0}: {1}').format('ip_admin_eth0', 'error')
#
with warnings.catch_warnings(record=True) as w:
cfg.ip_admin_eth0.ip_admin_eth0 = ['val1', 'val', 'val1']
assert len(w) == 1
assert w[0].message.opt == ip_admin_eth0
assert str(w[0].message) == 'invalid value val for option ip_admin_eth0: error'
assert str(w[0].message) == _('invalid value for option {0}: {1}').format('ip_admin_eth0', 'error')
#
warnings.resetwarnings()
with warnings.catch_warnings(record=True) as w:
cfg.ip_admin_eth0.ip_admin_eth0 = ['val1', 'val1', 'val']
assert len(w) == 1
assert w[0].message.opt == ip_admin_eth0
assert str(w[0].message) == 'invalid value val for option ip_admin_eth0: error'
assert str(w[0].message) == _('invalid value for option {0}: {1}').format('ip_admin_eth0', 'error')

View file

@ -9,7 +9,8 @@ from tiramisu.error import PropertiesOptionError
def make_description():
u1 = IntOption('u1', '', properties=('frozen', 'mandatory', 'disabled', ))
return OptionDescription('od1', '', [u1])
u2 = IntOption('u2', '', properties=('frozen', 'mandatory', 'disabled', ))
return OptionDescription('od1', '', [u1, u2])
def test_permissive():
@ -91,3 +92,108 @@ def test_invalid_permissive():
setting = config.cfgimpl_get_settings()
config.read_write()
raises(TypeError, "setting.setpermissive(['frozen', 'disabled',])")
def test_permissive_option():
descr = make_description()
u1 = descr.u1
config = Config(descr)
setting = config.cfgimpl_get_settings()
config.read_write()
props = []
try:
config.u1
except PropertiesOptionError as err:
props = err.proptype
assert props == ['disabled']
props = []
try:
config.u2
except PropertiesOptionError as err:
props = err.proptype
assert props == ['disabled']
setting.setpermissive(('disabled',), u1)
props = []
try:
config.u1
except PropertiesOptionError as err:
props = err.proptype
assert props == []
props = []
try:
config.u2
except PropertiesOptionError as err:
props = err.proptype
assert props == ['disabled']
setting.append('permissive')
config.u1
props = []
try:
config.u2
except PropertiesOptionError as err:
props = err.proptype
assert props == ['disabled']
setting.remove('permissive')
props = []
try:
config.u1
except PropertiesOptionError as err:
props = err.proptype
assert props == []
props = []
try:
config.u2
except PropertiesOptionError as err:
props = err.proptype
assert props == ['disabled']
def test_permissive_option_mandatory():
descr = make_description()
u1 = descr.u1
config = Config(descr)
setting = config.cfgimpl_get_settings()
config.read_only()
props = []
try:
config.u1
except PropertiesOptionError as err:
props = err.proptype
assert set(props) == set(['disabled', 'mandatory'])
setting.setpermissive(('mandatory', 'disabled',), u1)
setting.append('permissive')
config.u1
setting.remove('permissive')
try:
config.u1
except PropertiesOptionError as err:
props = err.proptype
assert set(props) == set(['disabled', 'mandatory'])
def test_permissive_option_frozen():
descr = make_description()
config = Config(descr)
u1 = descr.u1
setting = config.cfgimpl_get_settings()
config.read_write()
setting.setpermissive(('frozen', 'disabled'), u1)
config.u1 = 1
assert config.u1 == 1
setting.append('permissive')
assert config.u1 == 1
setting.remove('permissive')
assert config.u1 == 1
def test_invalid_option_permissive():
descr = make_description()
u1 = descr.u1
config = Config(descr)
setting = config.cfgimpl_get_settings()
config.read_write()
raises(TypeError, "setting.setpermissive(['frozen', 'disabled',], u1)")

View file

@ -26,6 +26,20 @@ def test_requires():
assert props == ['disabled']
def test_requires_invalid():
a = BoolOption('activate_service', '', True)
raises(ValueError, "IPOption('ip_address_service', '', requires='string')")
raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': False, 'action': 'disabled', 'unknown': True}])")
raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': False}])")
raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'action': 'disabled'}])")
raises(ValueError, "IPOption('ip_address_service', '', requires=[{'expected': False, 'action': 'disabled'}])")
raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': False, 'action': 'disabled', 'inverse': 'string'}])")
raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': False, 'action': 'disabled', 'transitive': 'string'}])")
raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': False, 'action': 'disabled', 'same_action': 'string'}])")
raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': 'string', 'expected': False, 'action': 'disabled'}])")
raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': 'string', 'action': 'disabled'}])")
def test_requires_same_action():
a = BoolOption('activate_service', '', True)
b = BoolOption('activate_service_web', '', True,
@ -504,6 +518,11 @@ def test_requires_requirement_append():
c.cfgimpl_get_settings()[b].append("test")
def test_requires_different_inverse():
a = BoolOption('activate_service', '', True)
raises(ValueError, "IPOption('ip_address_service', '', requires=[{'option': a, 'expected': True, 'action': 'disabled', 'inverse': True}, {'option': a, 'expected': True, 'action': 'disabled', 'inverse': False}])")
def test_requires_recursive_path():
a = BoolOption('activate_service', '', True)
b = IPOption('ip_address_service', '',

View file

@ -3,9 +3,10 @@ import autopath
from py.test import raises
from tiramisu.config import Config, SubConfig
from tiramisu.option import ChoiceOption, BoolOption, IntOption, FloatOption, \
from tiramisu.option import ChoiceOption, BoolOption, IntOption, FloatOption,\
StrOption, SymLinkOption, UnicodeOption, IPOption, OptionDescription, \
PortOption, NetworkOption, NetmaskOption, DomainnameOption
PortOption, NetworkOption, NetmaskOption, DomainnameOption, EmailOption, \
URLOption, FilenameOption
def test_slots_option():
@ -35,6 +36,12 @@ def test_slots_option():
raises(AttributeError, "c.x = 1")
c = DomainnameOption('a', '')
raises(AttributeError, "c.x = 1")
c = EmailOption('a', '')
raises(AttributeError, "c.x = 1")
c = URLOption('a', '')
raises(AttributeError, "c.x = 1")
c = FilenameOption('a', '')
raises(AttributeError, "c.x = 1")
def test_slots_option_readonly():
@ -49,7 +56,10 @@ def test_slots_option_readonly():
j = NetworkOption('j', '')
k = NetmaskOption('k', '')
l = DomainnameOption('l', '')
m = OptionDescription('m', '', [a, b, c, d, e, g, h, i, j, k, l])
o = EmailOption('o', '')
p = URLOption('p', '')
q = FilenameOption('q', '')
m = OptionDescription('m', '', [a, b, c, d, e, g, h, i, j, k, l, o, p, q])
a._requires = 'a'
b._requires = 'b'
c._requires = 'c'
@ -62,6 +72,9 @@ def test_slots_option_readonly():
k._requires = 'k'
l._requires = 'l'
m._requires = 'm'
o._requires = 'o'
p._requires = 'p'
q._requires = 'q'
Config(m)
raises(AttributeError, "a._requires = 'a'")
raises(AttributeError, "b._requires = 'b'")
@ -75,6 +88,9 @@ def test_slots_option_readonly():
raises(AttributeError, "k._requires = 'k'")
raises(AttributeError, "l._requires = 'l'")
raises(AttributeError, "m._requires = 'm'")
raises(AttributeError, "o._requires = 'o'")
raises(AttributeError, "p._requires = 'p'")
raises(AttributeError, "q._requires = 'q'")
def test_slots_option_readonly_name():
@ -90,7 +106,10 @@ def test_slots_option_readonly_name():
j = NetworkOption('j', '')
k = NetmaskOption('k', '')
l = DomainnameOption('l', '')
m = OptionDescription('m', '', [a, b, c, d, e, f, g, h, i, j, k, l])
o = DomainnameOption('o', '')
p = DomainnameOption('p', '')
q = DomainnameOption('q', '')
m = OptionDescription('m', '', [a, b, c, d, e, f, g, h, i, j, k, l, o, p, q])
raises(AttributeError, "a._name = 'a'")
raises(AttributeError, "b._name = 'b'")
raises(AttributeError, "c._name = 'c'")
@ -104,6 +123,9 @@ def test_slots_option_readonly_name():
raises(AttributeError, "k._name = 'k'")
raises(AttributeError, "l._name = 'l'")
raises(AttributeError, "m._name = 'm'")
raises(AttributeError, "o._name = 'o'")
raises(AttributeError, "p._name = 'p'")
raises(AttributeError, "q._name = 'q'")
def test_slots_description():

View file

@ -318,3 +318,46 @@ def test_state_groupconfig():
delete_session('29090937')
except ConfigError:
pass
def test_state_unkown_setting_owner():
"""load an unknow _owner, should create it"""
assert not 'supernewuser' in owners.__dict__
loads("""ccopy_reg
_reconstructor
p0
(ctiramisu.setting
Settings
p1
c__builtin__
object
p2
Ntp3
Rp4
(dp5
S'_owner'
p6
S'supernewuser'
p7
sS'_p_'
p8
g0
(ctiramisu.storage.dictionary.setting
Settings
p9
g2
Ntp10
Rp11
(dp12
S'_cache'
p13
(dp14
sS'_permissives'
p15
(dp16
sS'_properties'
p17
(dp18
sbsb.
.""")
assert 'supernewuser' in owners.__dict__

View file

@ -20,15 +20,16 @@
# ____________________________________________________________
"enables us to carry out a calculation and return an option's value"
from tiramisu.error import PropertiesOptionError, ConfigError
from tiramisu.setting import multitypes
from tiramisu.i18n import _
# ____________________________________________________________
def carry_out_calculation(name, config, callback, callback_params,
def carry_out_calculation(option, config, callback, callback_params,
index=None, max_len=None):
"""a function that carries out a calculation for an option's value
:param name: the option name (`opt._name`)
:param name: the option
:param config: the context config in order to have
the whole options available
:param callback: the name of the callback function
@ -49,13 +50,13 @@ def carry_out_calculation(name, config, callback, callback_params,
Values could have multiple values only when key is ''.
* if no callback_params:
=> calculate()
=> calculate(<function func at 0x2092320>, [], {})
* if callback_params={'': ('yes',)}
=> calculate('yes')
=> calculate(<function func at 0x2092320>, ['yes'], {})
* if callback_params={'value': ('yes',)}
=> calculate(value='yes')
=> calculate(<function func at 0x165b320>, [], {'value': 'yes'})
* if callback_params={'': ('yes', 'no')}
=> calculate('yes', 'no')
@ -63,58 +64,71 @@ def carry_out_calculation(name, config, callback, callback_params,
* if callback_params={'value': ('yes', 'no')}
=> ValueError()
* if callback_params={'': (['yes', 'no'],)}
=> calculate(<function func at 0x176b320>, ['yes', 'no'], {})
* if callback_params={'value': ('yes', 'no')}
=> raises ValueError()
* if callback_params={'': ((opt1, False),)}
- a simple option:
opt1 == 11
=> calculate(11)
=> calculate(<function func at 0x1cea320>, [11], {})
- a multi option:
- a multi option and not master/slave:
opt1 == [1, 2, 3]
=> calculate(1)
=> calculate(2)
=> calculate(3)
=> calculate(<function func at 0x223c320>, [[1, 2, 3]], {})
- option is master or slave of opt1:
opt1 == [1, 2, 3]
=> calculate(<function func at 0x223c320>, [1], {})
=> calculate(<function func at 0x223c320>, [2], {})
=> calculate(<function func at 0x223c320>, [3], {})
- opt is a master or slave but not related to option:
opt1 == [1, 2, 3]
=> calculate(<function func at 0x11b0320>, [[1, 2, 3]], {})
* if callback_params={'value': ((opt1, False),)}
- a simple option:
opt1 == 11
=> calculate(value=11)
=> calculate(<function func at 0x17ff320>, [], {'value': 11})
- a multi option:
opt1 == [1, 2, 3]
=> calculate(value=1)
=> calculate(value=2)
=> calculate(value=3)
=> calculate(<function func at 0x1262320>, [], {'value': [1, 2, 3]})
* if callback_params={'': ((opt1, False), (opt2, False))}
- two single options
opt1 = 11
opt2 = 12
=> calculate(<function func at 0x217a320>, [11, 12], {})
- a multi option with a simple option
opt1 == [1, 2, 3]
opt2 == 11
=> calculate(1, 11)
=> calculate(2, 11)
=> calculate(3, 11)
opt2 == 12
=> calculate(<function func at 0x2153320>, [[1, 2, 3], 12], {})
- a multi option with an other multi option but with same length
opt1 == [1, 2, 3]
opt2 == [11, 12, 13]
=> calculate(1, 11)
=> calculate(2, 12)
=> calculate(3, 13)
=> calculate(<function func at 0x1981320>, [[1, 2, 3], [11, 12, 13]], {})
- a multi option with an other multi option but with different length
opt1 == [1, 2, 3]
opt2 == [11, 12]
=> ConfigError()
=> calculate(<function func at 0x2384320>, [[1, 2, 3], [11, 12]], {})
- a multi option without value with a simple option
opt1 == []
opt2 == 11
=> []
=> calculate(<function func at 0xb65320>, [[], 12], {})
* if callback_params={'value': ((opt1, False), (opt2, False))}
=> ConfigError()
=> raises ValueError()
If index is not None, return a value, otherwise return:
@ -133,29 +147,36 @@ def carry_out_calculation(name, config, callback, callback_params,
for callbk in callbacks:
if isinstance(callbk, tuple):
# callbk is something link (opt, True|False)
option, force_permissive = callbk
opt, force_permissive = callbk
path = config.cfgimpl_get_description().impl_get_path_by_opt(
option)
opt)
# get value
try:
value = config._getattr(path, force_permissive=True)
value = config._getattr(path, force_permissive=True, validate=False)
# convert to list, not modifie this multi
if value.__class__.__name__ == 'Multi':
value = list(value)
except PropertiesOptionError as err:
if force_permissive:
continue
raise ConfigError(_('unable to carry out a calculation, '
'option {0} has properties: {1} for: '
'{2}').format(option._name,
'{2}').format(opt._name,
err.proptype,
name))
is_multi = option.impl_is_multi()
option._name))
is_multi = False
if opt.impl_is_multi():
#opt is master, search if option is a slave
if opt.impl_get_multitype() == multitypes.master:
if option in opt.impl_get_master_slaves():
is_multi = True
#opt is slave, search if option is an other slaves
elif opt.impl_get_multitype() == multitypes.slave:
if option in opt.impl_get_master_slaves().impl_get_master_slaves():
is_multi = True
if is_multi:
len_value = len(value)
if len_multi is not None and len_multi != len_value:
raise ConfigError(_('unable to carry out a '
'calculation, option value with'
' multi types must have same '
'length for: {0}').format(name))
len_multi = len_value
len_multi = len(value)
one_is_multi = True
tcparams.setdefault(key, []).append((value, is_multi))
else:
@ -168,16 +189,9 @@ def carry_out_calculation(name, config, callback, callback_params,
if one_is_multi:
ret = []
if index:
if index < len_multi:
range_ = [index]
else:
range_ = []
ret = None
range_ = [index]
else:
if max_len and max_len < len_multi:
range_ = range(max_len)
else:
range_ = range(len_multi)
range_ = range(len_multi)
for incr in range_:
args = []
kwargs = {}
@ -196,10 +210,7 @@ def carry_out_calculation(name, config, callback, callback_params,
if index:
ret = calc
else:
if isinstance(calc, list):
ret.extend(calc)
else:
ret.append(calc)
ret.append(calc)
return ret
else:
# no value is multi
@ -213,7 +224,18 @@ def carry_out_calculation(name, config, callback, callback_params,
args.append(couple[0])
else:
kwargs[key] = couple[0]
return calculate(callback, args, kwargs)
ret = calculate(callback, args, kwargs)
if callback_params != {}:
if isinstance(ret, list) and max_len:
ret = ret[:max_len]
if len(ret) < max_len:
ret = ret + [None] * (max_len - len(ret))
if isinstance(ret, list) and index:
if len(ret) < index + 1:
ret = None
else:
ret = ret[index]
return ret
def calculate(callback, args, kwargs):

View file

@ -156,7 +156,15 @@ class SubConfig(object):
__repr__ = __str__
def _cfgimpl_get_context(self):
return self._impl_context()
"""context could be None, we need to test it
context is None only if all reference to `Config` object is deleted
(for example we delete a `Config` and we manipulate a reference to
old `SubConfig`, `Values`, `Multi` or `Settings`)
"""
context = self._impl_context()
if context is None:
raise ConfigError(_('the context does not exist anymore'))
return context
def cfgimpl_get_description(self):
if self._impl_descr is None:
@ -250,7 +258,8 @@ class SubConfig(object):
force_properties=force_properties,
force_permissive=force_permissive)
def find(self, bytype=None, byname=None, byvalue=None, type_='option'):
def find(self, bytype=None, byname=None, byvalue=None, type_='option',
check_properties=True):
"""
finds a list of options recursively in the config
@ -262,11 +271,11 @@ class SubConfig(object):
return self._cfgimpl_get_context()._find(bytype, byname, byvalue,
first=False,
type_=type_,
_subpath=self.cfgimpl_get_path()
)
_subpath=self.cfgimpl_get_path(),
check_properties=check_properties)
def find_first(self, bytype=None, byname=None, byvalue=None,
type_='option', display_error=True):
type_='option', display_error=True, check_properties=True):
"""
finds an option recursively in the config
@ -277,7 +286,8 @@ class SubConfig(object):
"""
return self._cfgimpl_get_context()._find(
bytype, byname, byvalue, first=True, type_=type_,
_subpath=self.cfgimpl_get_path(), display_error=display_error)
_subpath=self.cfgimpl_get_path(), display_error=display_error,
check_properties=check_properties)
def _find(self, bytype, byname, byvalue, first, type_='option',
_subpath=None, check_properties=True, display_error=True):
@ -734,4 +744,6 @@ def mandatory_warnings(config):
except PropertiesOptionError as err:
if err.proptype == ['mandatory']:
yield path
except ConfigError:
pass
config.cfgimpl_reset_cache(only=('values',))

View file

@ -40,9 +40,7 @@ forbidden_names = ('iter_all', 'iter_group', 'find', 'find_first',
def valid_name(name):
"an option's name is a str and does not start with 'impl' or 'cfgimpl'"
try:
name = str(name)
except:
if not isinstance(name, str):
return False
if re.match(name_regexp, name) is None and not name.startswith('_') \
and name not in forbidden_names \
@ -413,7 +411,7 @@ class Option(BaseOption):
else:
validator_params = {'': (val,)}
# Raise ValueError if not valid
carry_out_calculation(self._name, config=context,
carry_out_calculation(self, config=context,
callback=self._validator[0],
callback_params=validator_params)
@ -421,7 +419,11 @@ class Option(BaseOption):
if _value is None:
return
# option validation
self._validate(_value)
try:
self._validate(_value)
except ValueError as err:
raise ValueError(_('invalid value for option {0}: {1}'
'').format(self._name, err))
try:
# valid with self._validator
val_validator(_value)
@ -430,8 +432,8 @@ class Option(BaseOption):
descr._valid_consistency(self, _value, context, _index)
self._second_level_validation(_value)
except ValueError as err:
msg = _("invalid value {0} for option {1}: {2}").format(
_value, self._name, err)
msg = _("invalid value for option {0}: {1}").format(
self._name, err)
if self._warnings_only:
warnings.warn_explicit(ValueWarning(msg, self),
ValueWarning,
@ -447,17 +449,13 @@ class Option(BaseOption):
do_validation(value, force_index)
else:
if not isinstance(value, list):
raise ValueError(_("which must be a list").format(value,
self._name))
raise ValueError(_("invalid value {0} for option {1} which must be a list").format(value, self._name))
for index, val in enumerate(value):
do_validation(val, index)
def impl_getdefault(self, default_multi=False):
def impl_getdefault(self):
"accessing the default value"
if not default_multi or not self.impl_is_multi():
return self._default
else:
return self.getdefault_multi()
return self._default
def impl_getdefault_multi(self):
"accessing the default value for a multi"
@ -677,7 +675,7 @@ class BoolOption(Option):
def _validate(self, value):
if not isinstance(value, bool):
raise ValueError(_('value must be a boolean'))
raise ValueError(_('invalid boolean'))
class IntOption(Option):
@ -687,7 +685,7 @@ class IntOption(Option):
def _validate(self, value):
if not isinstance(value, int):
raise ValueError(_('value must be an integer'))
raise ValueError(_('invalid integer'))
class FloatOption(Option):
@ -697,7 +695,7 @@ class FloatOption(Option):
def _validate(self, value):
if not isinstance(value, float):
raise ValueError(_('value must be a float'))
raise ValueError(_('invalid float'))
class StrOption(Option):
@ -707,12 +705,11 @@ class StrOption(Option):
def _validate(self, value):
if not isinstance(value, str):
raise ValueError(_('value must be a string, not '
'{0}').format(type(value)))
raise ValueError(_('invalid string'))
if sys.version_info[0] >= 3:
#UnicodeOption is same has StrOption in python 3+
#UnicodeOption is same as StrOption in python 3+
class UnicodeOption(StrOption):
__slots__ = tuple()
pass
@ -725,7 +722,7 @@ else:
def _validate(self, value):
if not isinstance(value, unicode):
raise ValueError(_('value must be an unicode'))
raise ValueError(_('invalid unicode'))
class SymLinkOption(BaseOption):
@ -783,17 +780,23 @@ class IPOption(Option):
warnings_only=warnings_only)
def _validate(self, value):
# sometimes an ip term starts with a zero
# but this does not fit in some case, for example bind does not like it
for val in value.split('.'):
if val.startswith("0") and len(val) > 1:
raise ValueError(_('invalid IP'))
# 'standard' validation
try:
IP('{0}/32'.format(value))
except ValueError:
raise ValueError(_('invalid IP {0}').format(self._name))
raise ValueError(_('invalid IP'))
def _second_level_validation(self, value):
ip = IP('{0}/32'.format(value))
if not self._allow_reserved and ip.iptype() == 'RESERVED':
raise ValueError(_("IP mustn't not be in reserved class"))
raise ValueError(_("invalid IP, mustn't not be in reserved class"))
if self._private_only and not ip.iptype() == 'PRIVATE':
raise ValueError(_("IP must be in private class"))
raise ValueError(_("invalid IP, must be in private class"))
class PortOption(Option):
@ -853,16 +856,17 @@ class PortOption(Option):
if self._allow_range and ":" in str(value):
value = str(value).split(':')
if len(value) != 2:
raise ValueError('range must have two values only')
raise ValueError('invalid part, range must have two values '
'only')
if not value[0] < value[1]:
raise ValueError('first port in range must be'
raise ValueError('invalid port, first port in range must be'
' smaller than the second one')
else:
value = [value]
for val in value:
if not self._min_value <= int(val) <= self._max_value:
raise ValueError('port must be an between {0} and {1}'
raise ValueError('invalid port, must be an between {0} and {1}'
''.format(self._min_value, self._max_value))
@ -875,12 +879,12 @@ class NetworkOption(Option):
try:
IP(value)
except ValueError:
raise ValueError(_('invalid network address {0}').format(self._name))
raise ValueError(_('invalid network address'))
def _second_level_validation(self, value):
ip = IP(value)
if ip.iptype() == 'RESERVED':
raise ValueError(_("network shall not be in reserved class"))
raise ValueError(_("invalid network address, must not be in reserved class"))
class NetmaskOption(Option):
@ -892,7 +896,7 @@ class NetmaskOption(Option):
try:
IP('0.0.0.0/{0}'.format(value))
except ValueError:
raise ValueError(_('invalid netmask address {0}').format(self._name))
raise ValueError(_('invalid netmask address'))
def _cons_network_netmask(self, opts, vals):
#opts must be (netmask, network) options
@ -921,21 +925,21 @@ class NetmaskOption(Option):
except ValueError:
if not make_net:
msg = _("invalid network {0} ({1}) "
"with netmask {2} ({3}),"
"with netmask {2},"
" this network is an IP")
else:
if make_net:
msg = _("invalid IP {0} ({1}) with netmask {2} ({3}),"
msg = _("invalid IP {0} ({1}) with netmask {2},"
" this IP is a network")
except ValueError:
if make_net:
msg = _("invalid IP {0} ({1}) with netmask {2} ({3})")
msg = _('invalid IP {0} ({1}) with netmask {2}')
else:
msg = _("invalid network {0} ({1}) with netmask {2} ({3})")
msg = _('invalid network {0} ({1}) with netmask {2}')
if msg is not None:
raise ValueError(msg.format(val_ipnetwork, opts[1]._name,
val_netmask, self._name))
val_netmask))
class BroadcastOption(Option):
@ -946,7 +950,7 @@ class BroadcastOption(Option):
try:
IP('{0}/32'.format(value))
except ValueError:
raise ValueError(_('invalid broadcast address {0}').format(self._name))
raise ValueError(_('invalid broadcast address'))
def _cons_broadcast(self, opts, vals):
if len(vals) != 3:
@ -968,20 +972,39 @@ class DomainnameOption(Option):
domainname:
fqdn: with tld, not supported yet
"""
__slots__ = ('_type', '_allow_ip')
__slots__ = ('_type', '_allow_ip', '_allow_without_dot', '_domain_re')
_opt_type = 'domainname'
def __init__(self, name, doc, default=None, default_multi=None,
requires=None, multi=False, callback=None,
callback_params=None, validator=None, validator_params=None,
properties=None, allow_ip=False, type_='domainname',
warnings_only=False):
warnings_only=False, allow_without_dot=False):
if type_ not in ['netbios', 'hostname', 'domainname']:
raise ValueError(_('unknown type_ {0} for hostname').format(type_))
self._type = type_
if allow_ip not in [True, False]:
raise ValueError(_('allow_ip must be a boolean'))
if allow_without_dot not in [True, False]:
raise ValueError(_('allow_without_dot must be a boolean'))
self._allow_ip = allow_ip
self._allow_without_dot = allow_without_dot
end = ''
extrachar = ''
extrachar_mandatory = ''
if self._type == 'netbios':
length = 14
elif self._type == 'hostname':
length = 62
elif self._type == 'domainname':
length = 62
if allow_without_dot is False:
extrachar_mandatory = '\.'
else:
extrachar = '\.'
end = '+[a-z]*'
self._domain_re = re.compile(r'^(?:[a-z][a-z\d\-{0}]{{,{1}}}{2}){3}$'
''.format(extrachar, length, extrachar_mandatory, end))
super(DomainnameOption, self).__init__(name, doc, default=default,
default_multi=default_multi,
callback=callback,
@ -1000,29 +1023,82 @@ class DomainnameOption(Option):
return
except ValueError:
pass
if self._type == 'netbios':
length = 15
extrachar = ''
elif self._type == 'hostname':
length = 63
extrachar = ''
elif self._type == 'domainname':
length = 255
extrachar = '\.'
if '.' not in value:
raise ValueError(_("invalid value for {0}, must have dot"
"").format(self._name))
if len(value) > length:
raise ValueError(_("invalid domainname's length for"
" {0} (max {1})").format(self._name, length))
if len(value) == 1:
raise ValueError(_("invalid domainname's length for {0} (min 2)"
"").format(self._name))
regexp = r'^[a-z]([a-z\d{0}-])*[a-z\d]$'.format(extrachar)
if re.match(regexp, value) is None:
if self._type == 'domainname' and not self._allow_without_dot and \
'.' not in value:
raise ValueError(_("invalid domainname, must have dot"))
if len(value) > 255:
raise ValueError(_("invalid domainname's length (max 255)"))
if len(value) < 2:
raise ValueError(_("invalid domainname's length (min 2)"))
if not self._domain_re.search(value):
raise ValueError(_('invalid domainname'))
class EmailOption(DomainnameOption):
__slots__ = tuple()
_opt_type = 'email'
username_re = re.compile(r"^[\w!#$%&'*+\-/=?^`{|}~.]+$")
def _validate(self, value):
splitted = value.split('@', 1)
try:
username, domain = splitted
except ValueError:
raise ValueError(_('invalid email address, should contains one @'
))
if not self.username_re.search(username):
raise ValueError(_('invalid username in email address'))
super(EmailOption, self)._validate(domain)
class URLOption(DomainnameOption):
__slots__ = tuple()
_opt_type = 'url'
proto_re = re.compile(r'(http|https)://')
path_re = re.compile(r"^[a-z0-9\-\._~:/\?#\[\]@!%\$&\'\(\)\*\+,;=]+$")
def _validate(self, value):
match = self.proto_re.search(value)
if not match:
raise ValueError(_('invalid url, should start with http:// or '
'https://'))
value = value[len(match.group(0)):]
# get domain/files
splitted = value.split('/', 1)
try:
domain, files = splitted
except ValueError:
domain = value
files = None
# if port in domain
splitted = domain.split(':', 1)
try:
domain, port = splitted
except ValueError:
domain = splitted[0]
port = 0
if not 0 <= int(port) <= 65535:
raise ValueError(_('invalid url, port must be an between 0 and '
'65536'))
# validate domainname
super(URLOption, self)._validate(domain)
# validate file
if files is not None and files != '' and not self.path_re.search(files):
raise ValueError(_('invalid url, should ends with filename'))
class FilenameOption(Option):
__slots__ = tuple()
_opt_type = 'file'
path_re = re.compile(r"^[a-zA-Z0-9\-\._~/+]+$")
def _validate(self, value):
match = self.path_re.search(value)
if not match:
raise ValueError(_('invalid filename'))
class OptionDescription(BaseOption):
"""Config's schema (organisation, group) and container of Options
The `OptionsDescription` objects lives in the `tiramisu.config.Config`.
@ -1177,7 +1253,6 @@ class OptionDescription(BaseOption):
self._group_type = group_type
if isinstance(group_type, groups.MasterGroupType):
#if master (same name has group) is set
identical_master_child_name = False
#for collect all slaves
slaves = []
master = None
@ -1194,7 +1269,6 @@ class OptionDescription(BaseOption):
": this option is not a multi"
"").format(child._name, self._name))
if child._name == self._name:
identical_master_child_name = True
child._multitype = multitypes.master
master = child
else:
@ -1203,14 +1277,18 @@ class OptionDescription(BaseOption):
raise ValueError(_('master group with wrong'
' master name for {0}'
).format(self._name))
if master._callback is not None and master._callback[1] is not None:
for key, callbacks in master._callback[1].items():
for callbk in callbacks:
if isinstance(callbk, tuple):
if callbk[0] in slaves:
raise ValueError(_("callback of master's option shall "
"not refered a slave's ones"))
master._master_slaves = tuple(slaves)
for child in self.impl_getchildren():
if child != master:
child._master_slaves = master
child._multitype = multitypes.slave
if not identical_master_child_name:
raise ValueError(_("no child has same nom has master group"
" for: {0}").format(self._name))
else:
raise ValueError(_('group_type: {0}'
' not allowed').format(group_type))

View file

@ -24,7 +24,7 @@ from time import time
from copy import copy
import weakref
from tiramisu.error import (RequirementError, PropertiesOptionError,
ConstError)
ConstError, ConfigError)
from tiramisu.i18n import _
@ -242,6 +242,14 @@ multitypes = MultiTypeModule()
populate_multitypes()
# ____________________________________________________________
class Undefined():
pass
undefined = Undefined()
# ____________________________________________________________
class Property(object):
"a property is responsible of the option's value access rules"
@ -254,6 +262,11 @@ class Property(object):
self._properties = prop
def append(self, propname):
"""Appends a property named propname
:param propname: a predefined or user defined property name
:type propname: string
"""
if self._opt is not None and self._opt._calc_properties is not None \
and propname in self._opt._calc_properties:
raise ValueError(_('cannot append {0} property for option {1}: '
@ -263,12 +276,29 @@ class Property(object):
self._setting._setproperties(self._properties, self._opt, self._path)
def remove(self, propname):
"""Removes a property named propname
:param propname: a predefined or user defined property name
:type propname: string
"""
if propname in self._properties:
self._properties.remove(propname)
self._setting._setproperties(self._properties, self._opt,
self._path)
def extend(self, propnames):
"""Extends properties to the existing properties
:param propnames: an iterable made of property names
:type propnames: iterable of string
"""
for propname in propnames:
self.append(propname)
def reset(self):
"""resets the properties (does not **clear** the properties,
default properties are still present)
"""
self._setting.reset(_path=self._path)
def __contains__(self, propname):
@ -280,7 +310,7 @@ class Property(object):
#____________________________________________________________
class Settings(object):
"``Config()``'s configuration options"
"``config.Config()``'s configuration options settings"
__slots__ = ('context', '_owner', '_p_', '__weakref__')
def __init__(self, context, storage):
@ -298,6 +328,17 @@ class Settings(object):
self.context = weakref.ref(context)
self._p_ = storage
def _getcontext(self):
"""context could be None, we need to test it
context is None only if all reference to `Config` object is deleted
(for example we delete a `Config` and we manipulate a reference to
old `SubConfig`, `Values`, `Multi` or `Settings`)
"""
context = self.context()
if context is None:
raise ConfigError(_('the context does not exist anymore'))
return context
#____________________________________________________________
# properties methods
def __contains__(self, propname):
@ -322,12 +363,12 @@ class Settings(object):
raise ValueError(_('opt and all_properties must not be set '
'together in reset'))
if all_properties:
self._p_.reset_all_propertives()
self._p_.reset_all_properties()
else:
if opt is not None and _path is None:
_path = self._get_path_by_opt(opt)
self._p_.reset_properties(_path)
self.context().cfgimpl_reset_cache()
self._getcontext().cfgimpl_reset_cache()
def _getproperties(self, opt=None, path=None, is_apply_req=True):
if opt is None:
@ -380,7 +421,7 @@ class Settings(object):
self._p_.reset_properties(path)
else:
self._p_.setproperties(path, properties)
self.context().cfgimpl_reset_cache()
self._getcontext().cfgimpl_reset_cache()
#____________________________________________________________
def validate_properties(self, opt_or_descr, is_descr, is_write, path,
@ -406,10 +447,12 @@ class Settings(object):
"""
# opt properties
properties = copy(self._getproperties(opt_or_descr, path))
self_properties = copy(self._getproperties())
# remove opt permissive
# permissive affect option's permission with or without permissive
# global property
properties -= self._p_.getpermissive(path)
# remove global permissive if need
self_properties = copy(self._getproperties())
if force_permissive is True or 'permissive' in self_properties:
properties -= self._p_.getpermissive()
if force_permissives is not None:
@ -426,7 +469,7 @@ class Settings(object):
properties -= frozenset(('mandatory', 'frozen'))
else:
if 'mandatory' in properties and \
not self.context().cfgimpl_get_values()._isempty(
not self._getcontext().cfgimpl_get_values()._isempty(
opt_or_descr, value):
properties.remove('mandatory')
if is_write and 'everything_frozen' in self_properties:
@ -549,6 +592,7 @@ class Settings(object):
# filters the callbacks
calc_properties = set()
context = self._getcontext()
for requires in opt._requires:
for require in requires:
option, expected, action, inverse, \
@ -560,8 +604,7 @@ class Settings(object):
" '{0}' with requirement on: "
"'{1}'").format(path, reqpath))
try:
value = self.context()._getattr(reqpath,
force_permissive=True)
value = context._getattr(reqpath, force_permissive=True)
except PropertiesOptionError as err:
if not transitive:
continue
@ -590,7 +633,7 @@ class Settings(object):
:param opt: `Option`'s object
:returns: path
"""
return self.context().cfgimpl_get_description().impl_get_path_by_opt(opt)
return self._getcontext().cfgimpl_get_description().impl_get_path_by_opt(opt)
def get_modified_properties(self):
return self._p_.get_modified_properties()

View file

@ -31,7 +31,7 @@ class Settings(Cache):
self._permissives = {}
super(Settings, self).__init__(storage)
# propertives
# properties
def setproperties(self, path, properties):
self._properties[path] = properties
@ -41,7 +41,7 @@ class Settings(Cache):
def hasproperties(self, path):
return path in self._properties
def reset_all_propertives(self):
def reset_all_properties(self):
self._properties.clear()
def reset_properties(self, path):

View file

@ -33,7 +33,7 @@ class Settings(Sqlite3DB):
self._storage.execute(settings_table, commit=False)
self._storage.execute(permissives_table)
# propertives
# properties
def setproperties(self, path, properties):
path = self._sqlite_encode_path(path)
self._storage.execute("DELETE FROM property WHERE path = ?", (path,),
@ -56,7 +56,7 @@ class Settings(Sqlite3DB):
return self._storage.select("SELECT properties FROM property WHERE "
"path = ?", (path,)) is not None
def reset_all_propertives(self):
def reset_all_properties(self):
self._storage.execute("DELETE FROM property")
def reset_properties(self, path):

View file

@ -22,7 +22,7 @@ from copy import copy
import sys
import weakref
from tiramisu.error import ConfigError, SlaveError
from tiramisu.setting import owners, multitypes, expires_time
from tiramisu.setting import owners, multitypes, expires_time, undefined
from tiramisu.autolib import carry_out_calculation
from tiramisu.i18n import _
from tiramisu.option import SymLinkOption
@ -46,13 +46,24 @@ class Values(object):
# the storage type is dictionary or sqlite3
self._p_ = storage
def _getcontext(self):
"""context could be None, we need to test it
context is None only if all reference to `Config` object is deleted
(for example we delete a `Config` and we manipulate a reference to
old `SubConfig`, `Values`, `Multi` or `Settings`)
"""
context = self.context()
if context is None:
raise ConfigError(_('the context does not exist anymore'))
return context
def _getdefault(self, opt):
"""
actually retrieves the default value
:param opt: the `option.Option()` object
"""
meta = self.context().cfgimpl_get_meta()
meta = self._getcontext().cfgimpl_get_meta()
if meta is not None:
value = meta.cfgimpl_get_values()[opt]
else:
@ -62,7 +73,7 @@ class Values(object):
else:
return value
def _getvalue(self, opt, path, validate=True):
def _getvalue(self, opt, path):
"""actually retrieves the value
:param opt: the `option.Option()` object
@ -71,14 +82,9 @@ class Values(object):
if not self._p_.hasvalue(path):
# if there is no value
value = self._getdefault(opt)
if opt.impl_is_multi():
value = Multi(value, self.context, opt, path, validate)
else:
# if there is a value
value = self._p_.getvalue(path)
if opt.impl_is_multi() and not isinstance(value, Multi):
# load value so don't need to validate if is not a Multi
value = Multi(value, self.context, opt, path, validate=False)
return value
def get_modified_values(self):
@ -105,11 +111,11 @@ class Values(object):
if path is None:
path = self._get_opt_path(opt)
if self._p_.hasvalue(path):
setting = self.context().cfgimpl_get_settings()
context = self._getcontext()
setting = context.cfgimpl_get_settings()
opt.impl_validate(opt.impl_getdefault(),
self.context(),
'validator' in setting)
self.context().cfgimpl_reset_cache()
context, 'validator' in setting)
context.cfgimpl_reset_cache()
if (opt.impl_is_multi() and
opt.impl_get_multitype() == multitypes.master):
for slave in opt.impl_get_master_slaves():
@ -137,7 +143,7 @@ class Values(object):
callback, callback_params = opt._callback
if callback_params is None:
callback_params = {}
return carry_out_calculation(opt._name, config=self.context(),
return carry_out_calculation(opt, config=self._getcontext(),
callback=callback,
callback_params=callback_params,
index=index, max_len=max_len)
@ -151,7 +157,7 @@ class Values(object):
if path is None:
path = self._get_opt_path(opt)
ntime = None
setting = self.context().cfgimpl_get_settings()
setting = self._getcontext().cfgimpl_get_settings()
if 'cache' in setting and self._p_.hascache(path):
if 'expire' in setting:
ntime = int(time())
@ -176,7 +182,8 @@ class Values(object):
def _getitem(self, opt, path, validate, force_permissive, force_properties,
validate_properties):
# options with callbacks
setting = self.context().cfgimpl_get_settings()
context = self._getcontext()
setting = context.cfgimpl_get_settings()
is_frozen = 'frozen' in setting[opt]
# For calculating properties, we need value (ie for mandatory value).
# If value is calculating with a PropertiesOptionError's option
@ -186,7 +193,7 @@ class Values(object):
# ConfigError if properties did not raise.
config_error = None
force_permissives = None
# if value is callback and is not set
# if value has callback and is not set
# or frozen with force_default_on_freeze
if opt.impl_has_callback() and (
self._is_default_owner(path) or
@ -196,7 +203,7 @@ class Values(object):
if (opt.impl_is_multi() and
opt.impl_get_multitype() == multitypes.slave):
masterp = self._get_opt_path(opt.impl_get_master_slaves())
mastervalue = getattr(self.context(), masterp)
mastervalue = context._getattr(masterp, validate=validate)
lenmaster = len(mastervalue)
if lenmaster == 0:
value = []
@ -228,9 +235,12 @@ class Values(object):
if opt.impl_is_multi():
value = Multi(value, self.context, opt, path, validate)
else:
value = self._getvalue(opt, path, validate)
value = self._getvalue(opt, path)
if opt.impl_is_multi():
# load value so don't need to validate if is not a Multi
value = Multi(value, self.context, opt, path, validate=validate)
if config_error is None and validate:
opt.impl_validate(value, self.context(), 'validator' in setting)
opt.impl_validate(value, context, 'validator' in setting)
if config_error is None and self._is_default_owner(path) and \
'force_store_value' in setting[opt]:
self.setitem(opt, value, path, is_write=False)
@ -251,24 +261,45 @@ class Values(object):
# is_write is, for example, used with "force_store_value"
# user didn't change value, so not write
# valid opt
opt.impl_validate(value, self.context(),
'validator' in self.context().cfgimpl_get_settings())
if opt.impl_is_multi() and not isinstance(value, Multi):
context = self._getcontext()
opt.impl_validate(value, context,
'validator' in context.cfgimpl_get_settings())
if opt.impl_is_multi():
value = Multi(value, self.context, opt, path, setitem=True)
# Save old value
if opt.impl_get_multitype() == multitypes.master and \
self._p_.hasvalue(path):
old_value = self._p_.getvalue(path)
old_owner = self._p_.getowner(path, None)
else:
old_value = undefined
old_owner = undefined
self._setvalue(opt, path, value, force_permissive=force_permissive,
is_write=is_write)
if opt.impl_is_multi() and opt.impl_get_multitype() == multitypes.master:
try:
value._valid_master()
except Exception, err:
if old_value is not undefined:
self._p_.setvalue(path, old_value, old_owner)
else:
self._p_.resetvalue(path)
raise err
def _setvalue(self, opt, path, value, force_permissive=False,
force_properties=None,
is_write=True, validate_properties=True):
self.context().cfgimpl_reset_cache()
context = self._getcontext()
context.cfgimpl_reset_cache()
if validate_properties:
setting = self.context().cfgimpl_get_settings()
setting = context.cfgimpl_get_settings()
setting.validate_properties(opt, False, is_write,
value=value, path=path,
force_permissive=force_permissive,
force_properties=force_properties)
owner = self.context().cfgimpl_get_settings().getowner()
owner = context.cfgimpl_get_settings().getowner()
if isinstance(value, Multi):
value = list(value)
self._p_.setvalue(path, value, owner)
def getowner(self, opt):
@ -285,7 +316,7 @@ class Values(object):
def _getowner(self, path):
owner = self._p_.getowner(path, owners.default)
meta = self.context().cfgimpl_get_meta()
meta = self._getcontext().cfgimpl_get_meta()
if owner is owners.default and meta is not None:
owner = meta.cfgimpl_get_values()._getowner(path)
return owner
@ -337,7 +368,7 @@ class Values(object):
:param opt: the `option.Option` object
:returns: a string with points like "gc.dummy.my_option"
"""
return self.context().cfgimpl_get_description().impl_get_path_by_opt(opt)
return self._getcontext().cfgimpl_get_description().impl_get_path_by_opt(opt)
# information
def set_information(self, key, value):
@ -389,6 +420,8 @@ class Multi(list):
:param opt: the option object that have this Multi value
:param setitem: only if set a value
"""
if isinstance(value, Multi):
raise ValueError(_('{0} is already a Multi ').format(opt._name))
self.opt = opt
self.path = path
if not isinstance(context, weakref.ReferenceType):
@ -398,21 +431,32 @@ class Multi(list):
value = [value]
if validate and self.opt.impl_get_multitype() == multitypes.slave:
value = self._valid_slave(value, setitem)
elif validate and self.opt.impl_get_multitype() == multitypes.master:
self._valid_master(value)
elif not setitem and validate and \
self.opt.impl_get_multitype() == multitypes.master:
self._valid_master()
super(Multi, self).__init__(value)
def _getcontext(self):
"""context could be None, we need to test it
context is None only if all reference to `Config` object is deleted
(for example we delete a `Config` and we manipulate a reference to
old `SubConfig`, `Values`, `Multi` or `Settings`)
"""
context = self.context()
if context is None:
raise ConfigError(_('the context does not exist anymore'))
return context
def _valid_slave(self, value, setitem):
#if slave, had values until master's one
values = self.context().cfgimpl_get_values()
masterp = self.context().cfgimpl_get_description().impl_get_path_by_opt(
context = self._getcontext()
values = context.cfgimpl_get_values()
masterp = context.cfgimpl_get_description().impl_get_path_by_opt(
self.opt.impl_get_master_slaves())
mastervalue = getattr(self.context(), masterp)
mastervalue = context._getattr(masterp, validate=False)
masterlen = len(mastervalue)
valuelen = len(value)
is_default_owner = not values._is_default_owner(self.path) or setitem
if valuelen > masterlen or (valuelen < masterlen and
is_default_owner):
if valuelen > masterlen or (valuelen < masterlen and setitem):
raise SlaveError(_("invalid len for the slave: {0}"
" which has {1} as master").format(
self.opt._name, masterp))
@ -429,59 +473,43 @@ class Multi(list):
#else: same len so do nothing
return value
def _valid_master(self, value):
masterlen = len(value)
values = self.context().cfgimpl_get_values()
def _valid_master(self):
#masterlen = len(value)
values = self._getcontext().cfgimpl_get_values()
for slave in self.opt._master_slaves:
path = values._get_opt_path(slave)
if not values._is_default_owner(path):
value_slave = values._getvalue(slave, path)
if len(value_slave) > masterlen:
raise SlaveError(_("invalid len for the master: {0}"
" which has {1} as slave with"
" greater len").format(
self.opt._name, slave._name))
elif len(value_slave) < masterlen:
for num in range(0, masterlen - len(value_slave)):
if slave.impl_has_callback():
# if callback add a value, but this value will not
# change anymore automaticly (because this value
# has owner)
index = value_slave.__len__()
value_slave.append(
values._getcallback_value(slave, index=index),
force=True)
else:
value_slave.append(slave.impl_getdefault_multi(),
force=True)
Multi(values._getvalue(slave, path), self.context, slave, path)
def __setitem__(self, index, value):
self._validate(value, index)
#assume not checking mandatory property
super(Multi, self).__setitem__(index, value)
self.context().cfgimpl_get_values()._setvalue(self.opt, self.path, self)
self._getcontext().cfgimpl_get_values()._setvalue(self.opt, self.path, self)
def append(self, value, force=False):
def append(self, value=undefined, force=False):
"""the list value can be updated (appened)
only if the option is a master
"""
context = self._getcontext()
if not force:
if self.opt.impl_get_multitype() == multitypes.slave:
raise SlaveError(_("cannot append a value on a multi option {0}"
" which is a slave").format(self.opt._name))
elif self.opt.impl_get_multitype() == multitypes.master:
values = self.context().cfgimpl_get_values()
if value is None and self.opt.impl_has_callback():
values = context.cfgimpl_get_values()
if value is undefined and self.opt.impl_has_callback():
value = values._getcallback_value(self.opt)
#Force None il return a list
if isinstance(value, list):
value = None
index = self.__len__()
if value is undefined:
value = self.opt.impl_getdefault_multi()
self._validate(value, index)
super(Multi, self).append(value)
self.context().cfgimpl_get_values()._setvalue(self.opt, self.path,
self,
validate_properties=not force)
context.cfgimpl_get_values()._setvalue(self.opt, self.path,
self,
validate_properties=not force)
if not force and self.opt.impl_get_multitype() == multitypes.master:
for slave in self.opt.impl_get_master_slaves():
path = values._get_opt_path(slave)
@ -490,16 +518,15 @@ class Multi(list):
dvalue = values._getcallback_value(slave, index=index)
else:
dvalue = slave.impl_getdefault_multi()
old_value = values.getitem(slave, path,
old_value = values.getitem(slave, path, validate=False,
validate_properties=False)
if len(old_value) < self.__len__():
values.getitem(slave, path,
validate_properties=False).append(
dvalue, force=True)
else:
values.getitem(slave, path,
validate_properties=False)[
index] = dvalue
if len(old_value) + 1 != self.__len__():
raise SlaveError(_("invalid len for the slave: {0}"
" which has {1} as master").format(
self.opt._name, self.__len__()))
values.getitem(slave, path, validate=False,
validate_properties=False).append(
dvalue, force=True)
def sort(self, cmp=None, key=None, reverse=False):
if self.opt.impl_get_multitype() in [multitypes.slave,
@ -512,7 +539,7 @@ class Multi(list):
super(Multi, self).sort(key=key, reverse=reverse)
else:
super(Multi, self).sort(cmp=cmp, key=key, reverse=reverse)
self.context().cfgimpl_get_values()._setvalue(self.opt, self.path, self)
self._getcontext().cfgimpl_get_values()._setvalue(self.opt, self.path, self)
def reverse(self):
if self.opt.impl_get_multitype() in [multitypes.slave,
@ -520,7 +547,7 @@ class Multi(list):
raise SlaveError(_("cannot reverse multi option {0} if master or "
"slave").format(self.opt._name))
super(Multi, self).reverse()
self.context().cfgimpl_get_values()._setvalue(self.opt, self.path, self)
self._getcontext().cfgimpl_get_values()._setvalue(self.opt, self.path, self)
def insert(self, index, obj):
if self.opt.impl_get_multitype() in [multitypes.slave,
@ -528,7 +555,7 @@ class Multi(list):
raise SlaveError(_("cannot insert multi option {0} if master or "
"slave").format(self.opt._name))
super(Multi, self).insert(index, obj)
self.context().cfgimpl_get_values()._setvalue(self.opt, self.path, self)
self._getcontext().cfgimpl_get_values()._setvalue(self.opt, self.path, self)
def extend(self, iterable):
if self.opt.impl_get_multitype() in [multitypes.slave,
@ -536,12 +563,12 @@ class Multi(list):
raise SlaveError(_("cannot extend multi option {0} if master or "
"slave").format(self.opt._name))
super(Multi, self).extend(iterable)
self.context().cfgimpl_get_values()._setvalue(self.opt, self.path, self)
self._getcontext().cfgimpl_get_values()._setvalue(self.opt, self.path, self)
def _validate(self, value, force_index):
if value is not None:
try:
self.opt.impl_validate(value, context=self.context(),
self.opt.impl_validate(value, context=self._getcontext(),
force_index=force_index)
except ValueError as err:
raise ValueError(_("invalid value {0} "
@ -559,19 +586,20 @@ class Multi(list):
:type force: boolean
:returns: item at index
"""
context = self._getcontext()
if not force:
if self.opt.impl_get_multitype() == multitypes.slave:
raise SlaveError(_("cannot pop a value on a multi option {0}"
" which is a slave").format(self.opt._name))
elif self.opt.impl_get_multitype() == multitypes.master:
if self.opt.impl_get_multitype() == multitypes.master:
for slave in self.opt.impl_get_master_slaves():
values = self.context().cfgimpl_get_values()
values = context.cfgimpl_get_values()
if not values.is_default_owner(slave):
#get multi without valid properties
values.getitem(slave,
values.getitem(slave, validate=False,
validate_properties=False
).pop(index, force=True)
#set value without valid properties
ret = super(Multi, self).pop(index)
self.context().cfgimpl_get_values()._setvalue(self.opt, self.path, self, validate_properties=not force)
context.cfgimpl_get_values()._setvalue(self.opt, self.path, self, validate_properties=not force)
return ret

View file

@ -1,105 +1,105 @@
msgid ""
msgstr ""
"Project-Id-Version: \n"
"Project-Id-Version: Tiramisu\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-09-28 19:06+CEST\n"
"POT-Creation-Date: 2014-01-25 11:30+CET\n"
"PO-Revision-Date: \n"
"Last-Translator: Emmanuel Garette <egarette@cadoles.com>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language-Team: Tiramisu's team <egarette@cadoles.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.5.4\n"
"Language: fr\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
"X-Poedit-SourceCharset: UTF-8\n"
#: tiramisu/autolib.py:144
#: tiramisu/autolib.py:159
msgid ""
"unable to carry out a calculation, option {0} has properties: {1} for: {2}"
msgstr ""
"impossible d'effectuer le calcul, l'option {0} a les propriétés : {1} pour : "
"{2}"
#: tiramisu/autolib.py:153
msgid ""
"unable to carry out a calculation, option value with multi types must have "
"same length for: {0}"
msgstr ""
"impossible d'effectuer le calcul, la valeur d'une option avec le type multi "
"doit avoir la même longueur pour : {0}"
#: tiramisu/config.py:51
#: tiramisu/config.py:52
msgid "descr must be an optiondescription, not {0}"
msgstr "descr doit être une optiondescription pas un {0}"
#: tiramisu/config.py:126
#: tiramisu/config.py:127
msgid "unknown group_type: {0}"
msgstr "group_type inconnu: {0}"
#: tiramisu/config.py:162
#: tiramisu/config.py:166 tiramisu/setting.py:339 tiramisu/value.py:57
#: tiramisu/value.py:427
msgid "the context does not exist anymore"
msgstr "le context n'existe plus"
#: tiramisu/config.py:171
msgid ""
"no option description found for this config (may be metaconfig without meta)"
msgstr ""
"pas d'option description trouvé pour cette config (peut être une metaconfig "
"sans meta)"
#: tiramisu/config.py:188
#: tiramisu/config.py:197
msgid "can't assign to an OptionDescription"
msgstr "ne peut pas attribuer une valeur à une OptionDescription"
#: tiramisu/config.py:319
#: tiramisu/config.py:330
msgid "unknown type_ type {0}for _find"
msgstr "type_ type {0} pour _find inconnu"
#: tiramisu/config.py:358
#: tiramisu/config.py:369
msgid "no option found in config with these criteria"
msgstr "aucune option trouvée dans la config avec ces critères"
#: tiramisu/config.py:408
#: tiramisu/config.py:419
msgid "make_dict can't filtering with value without option"
msgstr "make_dict ne peut filtrer sur une valeur mais sans option"
#: tiramisu/config.py:429
#: tiramisu/config.py:440
msgid "unexpected path {0}, should start with {1}"
msgstr "chemin imprévu {0}, devrait commencer par {1}"
#: tiramisu/config.py:489
#: tiramisu/config.py:500
msgid "opt in getowner must be an option not {0}"
msgstr "opt dans getowner doit être une option pas {0}"
#: tiramisu/option.py:68
#: tiramisu/option.py:67
msgid "invalid name: {0} for option"
msgstr "nom invalide : {0} pour l'option"
#: tiramisu/option.py:77
#: tiramisu/option.py:76
msgid "invalid properties type {0} for {1}, must be a tuple"
msgstr "type des properties invalide {0} pour {1}, doit être un tuple"
#: tiramisu/option.py:115
#: tiramisu/option.py:114
msgid "'{0}' ({1}) object attribute '{2}' is read-only"
msgstr "l'attribut {2} de l'objet '{0}' ({1}) est en lecture seule"
#: tiramisu/option.py:142 tiramisu/value.py:360
#: tiramisu/option.py:141 tiramisu/value.py:376
msgid "information's item not found: {0}"
msgstr "aucune config spécifiée alors que c'est nécessaire"
#: tiramisu/option.py:204
#: tiramisu/option.py:203
msgid "cannot serialize Option, only in OptionDescription"
msgstr "ne peut serialiser une Option, seulement via une OptionDescription"
#: tiramisu/option.py:307
#: tiramisu/option.py:306
msgid "a default_multi is set whereas multi is False in option: {0}"
msgstr ""
"une default_multi est renseignée alors que multi est False dans l'option : "
"{0}"
#: tiramisu/option.py:313
#: tiramisu/option.py:312
msgid "invalid default_multi value {0} for option {1}: {2}"
msgstr "la valeur default_multi est invalide {0} pour l'option {1} : {2}"
#: tiramisu/option.py:318
#: tiramisu/option.py:317
msgid "default value not allowed if option: {0} is calculated"
msgstr "la valeur par défaut n'est pas possible si l'option {0} est calculée"
#: tiramisu/option.py:321
#: tiramisu/option.py:320
msgid ""
"params defined for a callback function but no callback defined yet for "
"option {0}"
@ -107,221 +107,251 @@ msgstr ""
"params définis pour une fonction callback mais par de callback encore "
"définis pour l'option {0}"
#: tiramisu/option.py:360
#: tiramisu/option.py:359
msgid "option not in all_cons_opts"
msgstr "option non présentante dans all_cons_opts"
#: tiramisu/option.py:432 tiramisu/value.py:545
msgid "invalid value {0} for option {1}: {2}"
msgstr "valeur invalide {0} pour l'option {1} : {2}"
#: tiramisu/option.py:425 tiramisu/option.py:435
msgid "invalid value for option {0}: {1}"
msgstr "valeur invalide pour l'option {0} : {1}"
#: tiramisu/option.py:449
msgid "which must be a list"
msgstr "lequel doit être une liste"
#: tiramisu/option.py:452
msgid "invalid value {0} for option {1} which must be a list"
msgstr "valeur invalide pour l'option {0} : {1} laquelle doit être une liste"
#: tiramisu/option.py:509
#: tiramisu/option.py:508
msgid "consistency should be set with an option"
msgstr "consistency doit être configuré avec une option"
#: tiramisu/option.py:511
#: tiramisu/option.py:510
msgid "cannot add consistency with itself"
msgstr "ne peut ajouter une consistency avec lui même"
#: tiramisu/option.py:513
#: tiramisu/option.py:512
msgid "every options in consistency should be multi or none"
msgstr ""
"toutes les options d'une consistency devrait être multi ou ne pas l'être"
#: tiramisu/option.py:533
#: tiramisu/option.py:532
msgid "same value for {0} and {1}"
msgstr "même valeur pour {0} et {1}"
#: tiramisu/option.py:642
#: tiramisu/option.py:641
msgid "values must be a tuple for {0}"
msgstr "values doit être un tuple pour {0}"
#: tiramisu/option.py:645
#: tiramisu/option.py:644
msgid "open_values must be a boolean for {0}"
msgstr "open_values doit être un booléen pour {0}"
#: tiramisu/option.py:667
#: tiramisu/option.py:666
msgid "value {0} is not permitted, only {1} is allowed"
msgstr "valeur {0} n'est pas permis, seules {1} sont autorisées"
#: tiramisu/option.py:679
msgid "value must be a boolean"
msgstr "valeur doit être un booléen"
#: tiramisu/option.py:678
msgid "invalid boolean"
msgstr "booléen invalide"
#: tiramisu/option.py:689
msgid "value must be an integer"
msgstr "valeur doit être un nombre entier"
#: tiramisu/option.py:688
msgid "invalid integer"
msgstr "nombre invalide"
#: tiramisu/option.py:699
msgid "value must be a float"
msgstr "valeur doit être un nombre flottant"
#: tiramisu/option.py:698
msgid "invalid float"
msgstr "invalide nombre flottan"
#: tiramisu/option.py:709
msgid "value must be a string, not {0}"
msgstr "valeur doit être une chaîne, pas {0}"
#: tiramisu/option.py:708
msgid "invalid string"
msgstr "invalide caractère"
#: tiramisu/option.py:727
msgid "value must be an unicode"
msgstr "valeur doit être une valeur unicode"
#: tiramisu/option.py:725
msgid "invalid unicode"
msgstr "invalide unicode"
#: tiramisu/option.py:739
#: tiramisu/option.py:737
msgid "malformed symlinkoption must be an option for symlink {0}"
msgstr "symlinkoption mal formé, doit être une option pour symlink {0}"
#: tiramisu/option.py:788
msgid "invalid IP {0}"
msgstr "adresse IP invalide {0}"
#: tiramisu/option.py:787 tiramisu/option.py:792
msgid "invalid IP"
msgstr "adresse IP invalide"
#: tiramisu/option.py:793
msgid "IP mustn't not be in reserved class"
msgstr "IP ne doit pas être d'une classe reservée"
#: tiramisu/option.py:797
msgid "invalid IP, mustn't not be in reserved class"
msgstr "adresse IP invalide, ne doit pas être d'une classe reservée"
#: tiramisu/option.py:795
msgid "IP must be in private class"
msgstr "IP doit être dans la classe privée"
#: tiramisu/option.py:799
msgid "invalid IP, must be in private class"
msgstr "adresse IP invalide, doit être dans la classe privée"
#: tiramisu/option.py:833
#: tiramisu/option.py:837
msgid "inconsistency in allowed range"
msgstr "inconsistence dans la plage autorisée"
#: tiramisu/option.py:838
#: tiramisu/option.py:842
msgid "max value is empty"
msgstr "la valeur maximum est vide"
#: tiramisu/option.py:877
msgid "invalid network address {0}"
msgstr "adresse réseau invalide {0}"
#: tiramisu/option.py:882
msgid "network shall not be in reserved class"
msgstr "le réseau ne doit pas être dans la classe reservée"
msgid "invalid network address"
msgstr "adresse réseau invalide"
#: tiramisu/option.py:894
msgid "invalid netmask address {0}"
msgstr "masque de sous-réseau invalide {0}"
#: tiramisu/option.py:887
msgid "invalid network address, must not be in reserved class"
msgstr "adresse réseau invalide, ne doit pas être dans la classe reservée"
#: tiramisu/option.py:910
#: tiramisu/option.py:899
msgid "invalid netmask address"
msgstr "masque de sous-réseau invalide"
#: tiramisu/option.py:915
msgid "invalid len for opts"
msgstr "longueur invalide pour opts"
#: tiramisu/option.py:922
msgid "invalid network {0} ({1}) with netmask {2} ({3}), this network is an IP"
msgstr "réseau invalide {0} ({1}) avec masque {2} ({3}), ce réseau est une IP"
#: tiramisu/option.py:927
msgid "invalid IP {0} ({1}) with netmask {2} ({3}), this IP is a network"
msgstr "IP invalide {0} ({1}) avec masque {2} ({3}), cette IP est un réseau"
msgid "invalid network {0} ({1}) with netmask {2}, this network is an IP"
msgstr "réseau invalide {0} ({1}) avec masque {2}, ce réseau est une IP"
#: tiramisu/option.py:932
msgid "invalid IP {0} ({1}) with netmask {2} ({3})"
msgstr "IP invalide {0} ({1}) avec masque {2} ({3})"
msgid "invalid IP {0} ({1}) with netmask {2}, this IP is a network"
msgstr "IP invalide {0} ({1}) avec masque {2}, cette IP est un réseau"
#: tiramisu/option.py:934
msgid "invalid network {0} ({1}) with netmask {2} ({3})"
msgstr "réseau invalide {0} ({1}) avec masque {2} ({3})"
#: tiramisu/option.py:937
msgid "invalid IP {0} ({1}) with netmask {2}"
msgstr "IP invalide {0} ({1}) avec masque {2}"
#: tiramisu/option.py:948
msgid "invalid broadcast address {0}"
msgstr "adresse de broadcast invalide {0}"
#: tiramisu/option.py:939
msgid "invalid network {0} ({1}) with netmask {2}"
msgstr "réseau invalide {0} ({1}) avec masque {2}"
#: tiramisu/option.py:952
#: tiramisu/option.py:953
msgid "invalid broadcast address"
msgstr "adresse de broadcast invalide"
#: tiramisu/option.py:957
msgid "invalid len for vals"
msgstr "longueur invalide pour vals"
#: tiramisu/option.py:957
#: tiramisu/option.py:962
msgid ""
"invalid broadcast {0} ({1}) with network {2} ({3}) and netmask {4} ({5})"
msgstr ""
"Broadcast invalide {0} ({1}) avec le réseau {2} ({3}) et le masque {4} ({5})"
#: tiramisu/option.py:979
#: tiramisu/option.py:984
msgid "unknown type_ {0} for hostname"
msgstr "type_ inconnu {0} pour le nom d'hôte"
#: tiramisu/option.py:982
#: tiramisu/option.py:987
msgid "allow_ip must be a boolean"
msgstr "allow_ip doit être un booléen"
#: tiramisu/option.py:1012
msgid "invalid value for {0}, must have dot"
msgstr "valeur invalide pour {0}, doit avoir un point"
#: tiramisu/option.py:989
msgid "allow_without_dot must be a boolean"
msgstr "allow_without_dot doit être un booléen"
#: tiramisu/option.py:1015
msgid "invalid domainname's length for {0} (max {1})"
msgstr "longueur du nom de domaine invalide pour {0} (maximum {1})"
#: tiramisu/option.py:1028
msgid "invalid domainname, must have dot"
msgstr "nom de domaine invalide, doit avoir un point"
#: tiramisu/option.py:1018
msgid "invalid domainname's length for {0} (min 2)"
msgstr "longueur du nom de domaine invalide pour {0} (minimum 2)"
#: tiramisu/option.py:1030
msgid "invalid domainname's length (max 255)"
msgstr "longueur du nom de domaine invalide (maximum {1})"
#: tiramisu/option.py:1022
#: tiramisu/option.py:1032
msgid "invalid domainname's length (min 2)"
msgstr "longueur du nom de domaine invalide (minimum 2)"
#: tiramisu/option.py:1034
msgid "invalid domainname"
msgstr "nom de domaine invalide"
#: tiramisu/option.py:1049
#: tiramisu/option.py:1047
msgid "invalid email address, should contains one @"
msgstr "adresse email invalide, devrait contenir un @"
#: tiramisu/option.py:1050
msgid "invalid username in email address"
msgstr "nom d'utilisateur invalide dans une adresse email"
#: tiramisu/option.py:1063
msgid "invalid url, should start with http:// or https://"
msgstr "URL invalide, devrait démarré avec http:// ou https://"
#: tiramisu/option.py:1082
msgid "invalid url, port must be an between 0 and 65536"
msgstr "URL invalide, port doit être entre 0 et 65536"
#: tiramisu/option.py:1088
msgid "invalid url, should ends with filename"
msgstr "URL invalide, devrait finir avec un nom de fichier"
#: tiramisu/option.py:1099
msgid "invalid filename"
msgstr "nom de fichier invalide"
#: tiramisu/option.py:1126
msgid "duplicate option name: {0}"
msgstr "nom de l'option dupliqué : {0}"
#: tiramisu/option.py:1067
#: tiramisu/option.py:1144
msgid "unknown Option {0} in OptionDescription {1}"
msgstr "Option {0} inconnue pour l'OptionDescription {1}"
#: tiramisu/option.py:1118
#: tiramisu/option.py:1195
msgid "duplicate option: {0}"
msgstr "option dupliquée : {0}"
#: tiramisu/option.py:1148
#: tiramisu/option.py:1225
msgid "consistency with option {0} which is not in Config"
msgstr "consistency avec l'option {0} qui n'est pas dans une Config"
#: tiramisu/option.py:1156
#: tiramisu/option.py:1233
msgid "no option for path {0}"
msgstr "pas d'option pour le chemin {0}"
#: tiramisu/option.py:1162
#: tiramisu/option.py:1239
msgid "no option {0} found"
msgstr "pas d'option {0} trouvée"
#: tiramisu/option.py:1172
#: tiramisu/option.py:1249
msgid "cannot change group_type if already set (old {0}, new {1})"
msgstr "ne peut changer group_type si déjà spécifié (ancien {0}, nouveau {1})"
#: tiramisu/option.py:1185
#: tiramisu/option.py:1261
msgid "master group {0} shall not have a subgroup"
msgstr "groupe maître {0} ne doit pas avoir de sous-groupe"
#: tiramisu/option.py:1188
#: tiramisu/option.py:1264
msgid "master group {0} shall not have a symlinkoption"
msgstr "groupe maître {0} ne doit pas avoir de symlinkoption"
#: tiramisu/option.py:1191
#: tiramisu/option.py:1267
msgid "not allowed option {0} in group {1}: this option is not a multi"
msgstr ""
"option non autorisée {0} dans le groupe {1} : cette option n'est pas une "
"multi"
#: tiramisu/option.py:1202
#: tiramisu/option.py:1277
msgid "master group with wrong master name for {0}"
msgstr "le groupe maître avec un nom de maître érroné pour {0}"
#: tiramisu/option.py:1211
msgid "no child has same nom has master group for: {0}"
msgstr "pas d'enfant avec le nom du groupe maître pour {0} "
#: tiramisu/option.py:1285
msgid "callback of master's option shall not refered a slave's ones"
msgstr ""
"callback d'une variable maitre ne devrait pas référencer des variables "
"esclaves"
#: tiramisu/option.py:1214
#: tiramisu/option.py:1293
msgid "group_type: {0} not allowed"
msgstr "group_type : {0} non autorisé"
#: tiramisu/option.py:1306
#: tiramisu/option.py:1385
msgid "malformed requirements type for option: {0}, must be a dict"
msgstr ""
"type requirements malformé pour l'option : {0}, doit être un dictionnaire"
#: tiramisu/option.py:1323
#: tiramisu/option.py:1402
msgid ""
"malformed requirements for option: {0} require must have option, expected "
"and action keys"
@ -329,110 +359,110 @@ msgstr ""
"requirements malformé pour l'option : {0} l'exigence doit avoir les clefs "
"option, expected et action"
#: tiramisu/option.py:1328
#: tiramisu/option.py:1407
msgid "malformed requirements for option: {0} inverse must be boolean"
msgstr ""
"requirements mal formés pour l'option : {0} inverse doit être un booléen"
#: tiramisu/option.py:1332
#: tiramisu/option.py:1411
msgid "malformed requirements for option: {0} transitive must be boolean"
msgstr ""
"requirements mal formés pour l'option : {0} transitive doit être booléen"
#: tiramisu/option.py:1336
#: tiramisu/option.py:1415
msgid "malformed requirements for option: {0} same_action must be boolean"
msgstr ""
"requirements mal formés pour l'option : {0} same_action doit être un booléen"
#: tiramisu/option.py:1340
#: tiramisu/option.py:1419
msgid "malformed requirements must be an option in option {0}"
msgstr "requirements mal formés doit être une option dans l'option {0}"
#: tiramisu/option.py:1343
#: tiramisu/option.py:1422
msgid "malformed requirements option {0} should not be a multi"
msgstr "requirements mal formés l'option {0} ne doit pas être une multi"
#: tiramisu/option.py:1349
#: tiramisu/option.py:1428
msgid ""
"malformed requirements second argument must be valid for option {0}: {1}"
msgstr ""
"requirements mal formés deuxième argument doit être valide pour l'option "
"{0} : {1}"
#: tiramisu/option.py:1354
#: tiramisu/option.py:1433
msgid "inconsistency in action types for option: {0} action: {1}"
msgstr "incohérence dans les types action pour l'option : {0} action {1}"
#: tiramisu/option.py:1379
#: tiramisu/option.py:1458
msgid "{0} should be a function"
msgstr "{0} doit être une fonction"
#: tiramisu/option.py:1382
#: tiramisu/option.py:1461
msgid "{0}_params should be a dict"
msgstr "{0}_params devrait être un dict"
#: tiramisu/option.py:1385
#: tiramisu/option.py:1464
msgid "{0}_params with key {1} should not have length different to 1"
msgstr ""
"{0}_params avec la clef {1} devrait ne pas avoir une longueur différent de 1"
#: tiramisu/option.py:1389
#: tiramisu/option.py:1468
msgid "{0}_params should be tuple for key \"{1}\""
msgstr "{0}_params devrait être un tuple pour la clef \"{1}\""
#: tiramisu/option.py:1395
#: tiramisu/option.py:1474
msgid "validator not support tuple"
msgstr "validator n'accepte pas de tuple"
#: tiramisu/option.py:1398
#: tiramisu/option.py:1477
msgid "{0}_params should have an option not a {0} for first argument"
msgstr "{0}_params devrait avoir une option pas un {0} pour premier argument"
#: tiramisu/option.py:1402
#: tiramisu/option.py:1481
msgid "{0}_params should have a boolean not a {0} for second argument"
msgstr "{0}_params devrait avoir un boolean pas un {0} pour second argument"
#: tiramisu/setting.py:111
#: tiramisu/setting.py:116
msgid "can't rebind {0}"
msgstr "ne peut redéfinir ({0})"
#: tiramisu/setting.py:116
#: tiramisu/setting.py:121
msgid "can't unbind {0}"
msgstr "ne peut supprimer ({0})"
#: tiramisu/setting.py:254
#: tiramisu/setting.py:272
msgid "cannot append {0} property for option {1}: this property is calculated"
msgstr ""
"ne peut ajouter la propriété {0} dans l'option {1}: cette propriété est "
"calculée"
#: tiramisu/setting.py:317
#: tiramisu/setting.py:363
msgid "opt and all_properties must not be set together in reset"
msgstr "opt et all_properties ne doit pas être renseigné ensemble dans reset"
#: tiramisu/setting.py:332
#: tiramisu/setting.py:378
msgid "if opt is not None, path should not be None in _getproperties"
msgstr ""
"si opt n'est pas None, path devrait ne pas être à None dans _getproperties"
#: tiramisu/setting.py:435
#: tiramisu/setting.py:483
msgid "cannot change the value for option {0} this option is frozen"
msgstr ""
"ne peut modifier la valeur de l'option {0} cette option n'est pas modifiable"
#: tiramisu/setting.py:441
#: tiramisu/setting.py:489
msgid "trying to access to an option named: {0} with properties {1}"
msgstr "tentative d'accès à une option nommée : {0} avec les propriétés {1}"
#: tiramisu/setting.py:459
#: tiramisu/setting.py:507
msgid "permissive must be a tuple"
msgstr "permissive doit être un tuple"
#: tiramisu/setting.py:466 tiramisu/value.py:299
#: tiramisu/setting.py:514 tiramisu/value.py:315
msgid "invalid generic owner {0}"
msgstr "invalide owner générique {0}"
#: tiramisu/setting.py:553
#: tiramisu/setting.py:602
msgid ""
"malformed requirements imbrication detected for option: '{0}' with "
"requirement on: '{1}'"
@ -440,75 +470,101 @@ msgstr ""
"imbrication de requirements mal formés detectée pour l'option : '{0}' avec "
"requirement sur : '{1}'"
#: tiramisu/setting.py:565
#: tiramisu/setting.py:613
msgid "option '{0}' has requirement's property error: {1} {2}"
msgstr "l'option '{0}' a une erreur de propriété pour le requirement : {1} {2}"
#: tiramisu/storage/__init__.py:47
#: tiramisu/storage/__init__.py:52
msgid "storage_type is already set, cannot rebind it"
msgstr "storage_type est déjà défini, impossible de le redéfinir"
#: tiramisu/storage/__init__.py:81
#: tiramisu/storage/__init__.py:86
msgid "option {0} not already exists in storage {1}"
msgstr "option {0} n'existe pas dans l'espace de stockage {1}"
#: tiramisu/storage/dictionary/storage.py:37
#: tiramisu/storage/dictionary/storage.py:39
msgid "dictionary storage cannot delete session"
msgstr ""
"impossible de supprimer une session dans un espace de stockage dictionary"
#: tiramisu/storage/dictionary/storage.py:48
#: tiramisu/storage/dictionary/storage.py:50
msgid "session already used"
msgstr "session déjà utilisée"
#: tiramisu/storage/dictionary/storage.py:50
#: tiramisu/storage/dictionary/storage.py:52
msgid "a dictionary cannot be persistent"
msgstr "un espace de stockage dictionary ne peut être persistant"
#: tiramisu/value.py:306
#: tiramisu/value.py:322
msgid "no value for {0} cannot change owner to {1}"
msgstr "pas de valeur pour {0} ne peut changer d'utilisateur pour {1}"
#: tiramisu/value.py:414
#: tiramisu/value.py:442
msgid "invalid len for the slave: {0} which has {1} as master"
msgstr "longueur invalide pour une esclave : {0} qui a {1} comme maître"
#: tiramisu/value.py:438
#: tiramisu/value.py:466
msgid "invalid len for the master: {0} which has {1} as slave with greater len"
msgstr ""
"longueur invalide pour un maître : {0} qui a {1} une esclave avec une plus "
"grande longueur"
#: tiramisu/value.py:468
#: tiramisu/value.py:496
msgid "cannot append a value on a multi option {0} which is a slave"
msgstr "ne peut ajouter une valeur sur l'option multi {0} qui est une esclave"
#: tiramisu/value.py:505
#: tiramisu/value.py:535
msgid "cannot sort multi option {0} if master or slave"
msgstr "ne peut trier une option multi {0} pour une maître ou une esclave"
#: tiramisu/value.py:509
#: tiramisu/value.py:539
msgid "cmp is not permitted in python v3 or greater"
msgstr "cmp n'est pas permis en python v3 ou supérieure"
#: tiramisu/value.py:518
#: tiramisu/value.py:548
msgid "cannot reverse multi option {0} if master or slave"
msgstr "ne peut inverser une option multi {0} pour une maître ou une esclave"
#: tiramisu/value.py:526
#: tiramisu/value.py:556
msgid "cannot insert multi option {0} if master or slave"
msgstr "ne peut insérer une option multi {0} pour une maître ou une esclave"
#: tiramisu/value.py:534
#: tiramisu/value.py:564
msgid "cannot extend multi option {0} if master or slave"
msgstr "ne peut étendre une option multi {0} pour une maître ou une esclave"
#: tiramisu/value.py:562
#: tiramisu/value.py:575
msgid "invalid value {0} for option {1}: {2}"
msgstr "valeur invalide {0} pour l'option {1} : {2}"
#: tiramisu/value.py:593
msgid "cannot pop a value on a multi option {0} which is a slave"
msgstr "ne peut supprimer une valeur dans l'option multi {0} qui est esclave"
#~ msgid "invalid value {0} for option {1} which must be a list"
#~ msgstr "valeur invalide {0} pour l'option {1} qui doit être une liste"
#~ msgid ""
#~ "unable to carry out a calculation, option value with multi types must "
#~ "have same length for: {0}"
#~ msgstr ""
#~ "impossible d'effectuer le calcul, la valeur d'une option avec le type "
#~ "multi doit avoir la même longueur pour : {0}"
#~ msgid "no child has same nom has master group for: {0}"
#~ msgstr "pas d'enfant avec le nom du groupe maître pour {0} "
#~ msgid "value must be a boolean"
#~ msgstr "valeur doit être un booléen"
#~ msgid "value must be an integer"
#~ msgstr "valeur doit être un nombre entier"
#~ msgid "value must be a float"
#~ msgstr "valeur doit être un nombre flottant"
#~ msgid "value must be a string, not {0}"
#~ msgstr "valeur doit être une chaîne, pas {0}"
#~ msgid "value must be an unicode"
#~ msgstr "valeur doit être une valeur unicode"
#~ msgid "invalid value {0} for option {1} must be different as {2} option"
#~ msgstr ""

View file

@ -5,7 +5,7 @@
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"POT-Creation-Date: 2013-09-28 19:06+CEST\n"
"POT-Creation-Date: 2014-01-25 11:30+CET\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -15,455 +15,488 @@ msgstr ""
"Generated-By: pygettext.py 1.5\n"
#: tiramisu/autolib.py:144
#: tiramisu/autolib.py:159
msgid "unable to carry out a calculation, option {0} has properties: {1} for: {2}"
msgstr ""
#: tiramisu/autolib.py:153
msgid "unable to carry out a calculation, option value with multi types must have same length for: {0}"
msgstr ""
#: tiramisu/config.py:51
#: tiramisu/config.py:52
msgid "descr must be an optiondescription, not {0}"
msgstr ""
#: tiramisu/config.py:126
#: tiramisu/config.py:127
msgid "unknown group_type: {0}"
msgstr ""
#: tiramisu/config.py:162
#: tiramisu/config.py:166 tiramisu/setting.py:339 tiramisu/value.py:57
#: tiramisu/value.py:427
msgid "the context does not exist anymore"
msgstr ""
#: tiramisu/config.py:171
msgid "no option description found for this config (may be metaconfig without meta)"
msgstr ""
#: tiramisu/config.py:188
#: tiramisu/config.py:197
msgid "can't assign to an OptionDescription"
msgstr ""
#: tiramisu/config.py:319
#: tiramisu/config.py:330
msgid "unknown type_ type {0}for _find"
msgstr ""
#: tiramisu/config.py:358
#: tiramisu/config.py:369
msgid "no option found in config with these criteria"
msgstr ""
#: tiramisu/config.py:408
#: tiramisu/config.py:419
msgid "make_dict can't filtering with value without option"
msgstr ""
#: tiramisu/config.py:429
#: tiramisu/config.py:440
msgid "unexpected path {0}, should start with {1}"
msgstr ""
#: tiramisu/config.py:489
#: tiramisu/config.py:500
msgid "opt in getowner must be an option not {0}"
msgstr ""
#: tiramisu/option.py:68
#: tiramisu/option.py:67
msgid "invalid name: {0} for option"
msgstr ""
#: tiramisu/option.py:77
#: tiramisu/option.py:76
msgid "invalid properties type {0} for {1}, must be a tuple"
msgstr ""
#: tiramisu/option.py:115
#: tiramisu/option.py:114
msgid "'{0}' ({1}) object attribute '{2}' is read-only"
msgstr ""
#: tiramisu/option.py:142 tiramisu/value.py:360
#: tiramisu/option.py:141 tiramisu/value.py:376
msgid "information's item not found: {0}"
msgstr ""
#: tiramisu/option.py:204
#: tiramisu/option.py:203
msgid "cannot serialize Option, only in OptionDescription"
msgstr ""
#: tiramisu/option.py:307
#: tiramisu/option.py:306
msgid "a default_multi is set whereas multi is False in option: {0}"
msgstr ""
#: tiramisu/option.py:313
#: tiramisu/option.py:312
msgid "invalid default_multi value {0} for option {1}: {2}"
msgstr ""
#: tiramisu/option.py:318
#: tiramisu/option.py:317
msgid "default value not allowed if option: {0} is calculated"
msgstr ""
#: tiramisu/option.py:321
#: tiramisu/option.py:320
msgid "params defined for a callback function but no callback defined yet for option {0}"
msgstr ""
#: tiramisu/option.py:360
#: tiramisu/option.py:359
msgid "option not in all_cons_opts"
msgstr ""
#: tiramisu/option.py:432 tiramisu/value.py:545
msgid "invalid value {0} for option {1}: {2}"
#: tiramisu/option.py:425 tiramisu/option.py:435
msgid "invalid value for option {0}: {1}"
msgstr ""
#: tiramisu/option.py:449
msgid "which must be a list"
#: tiramisu/option.py:452
msgid "invalid value {0} for option {1} which must be a list"
msgstr ""
#: tiramisu/option.py:509
#: tiramisu/option.py:508
msgid "consistency should be set with an option"
msgstr ""
#: tiramisu/option.py:511
#: tiramisu/option.py:510
msgid "cannot add consistency with itself"
msgstr ""
#: tiramisu/option.py:513
#: tiramisu/option.py:512
msgid "every options in consistency should be multi or none"
msgstr ""
#: tiramisu/option.py:533
#: tiramisu/option.py:532
msgid "same value for {0} and {1}"
msgstr ""
#: tiramisu/option.py:642
#: tiramisu/option.py:641
msgid "values must be a tuple for {0}"
msgstr ""
#: tiramisu/option.py:645
#: tiramisu/option.py:644
msgid "open_values must be a boolean for {0}"
msgstr ""
#: tiramisu/option.py:667
#: tiramisu/option.py:666
msgid "value {0} is not permitted, only {1} is allowed"
msgstr ""
#: tiramisu/option.py:679
msgid "value must be a boolean"
#: tiramisu/option.py:678
msgid "invalid boolean"
msgstr ""
#: tiramisu/option.py:689
msgid "value must be an integer"
#: tiramisu/option.py:688
msgid "invalid integer"
msgstr ""
#: tiramisu/option.py:699
msgid "value must be a float"
#: tiramisu/option.py:698
msgid "invalid float"
msgstr ""
#: tiramisu/option.py:709
msgid "value must be a string, not {0}"
#: tiramisu/option.py:708
msgid "invalid string"
msgstr ""
#: tiramisu/option.py:727
msgid "value must be an unicode"
#: tiramisu/option.py:725
msgid "invalid unicode"
msgstr ""
#: tiramisu/option.py:739
#: tiramisu/option.py:737
msgid "malformed symlinkoption must be an option for symlink {0}"
msgstr ""
#: tiramisu/option.py:788
msgid "invalid IP {0}"
#: tiramisu/option.py:787 tiramisu/option.py:792
msgid "invalid IP"
msgstr ""
#: tiramisu/option.py:793
msgid "IP mustn't not be in reserved class"
#: tiramisu/option.py:797
msgid "invalid IP, mustn't not be in reserved class"
msgstr ""
#: tiramisu/option.py:795
msgid "IP must be in private class"
#: tiramisu/option.py:799
msgid "invalid IP, must be in private class"
msgstr ""
#: tiramisu/option.py:833
#: tiramisu/option.py:837
msgid "inconsistency in allowed range"
msgstr ""
#: tiramisu/option.py:838
#: tiramisu/option.py:842
msgid "max value is empty"
msgstr ""
#: tiramisu/option.py:877
msgid "invalid network address {0}"
msgstr ""
#: tiramisu/option.py:882
msgid "network shall not be in reserved class"
msgid "invalid network address"
msgstr ""
#: tiramisu/option.py:894
msgid "invalid netmask address {0}"
#: tiramisu/option.py:887
msgid "invalid network address, must not be in reserved class"
msgstr ""
#: tiramisu/option.py:910
#: tiramisu/option.py:899
msgid "invalid netmask address"
msgstr ""
#: tiramisu/option.py:915
msgid "invalid len for opts"
msgstr ""
#: tiramisu/option.py:922
msgid "invalid network {0} ({1}) with netmask {2} ({3}), this network is an IP"
msgstr ""
#: tiramisu/option.py:927
msgid "invalid IP {0} ({1}) with netmask {2} ({3}), this IP is a network"
msgid "invalid network {0} ({1}) with netmask {2}, this network is an IP"
msgstr ""
#: tiramisu/option.py:932
msgid "invalid IP {0} ({1}) with netmask {2} ({3})"
msgid "invalid IP {0} ({1}) with netmask {2}, this IP is a network"
msgstr ""
#: tiramisu/option.py:934
msgid "invalid network {0} ({1}) with netmask {2} ({3})"
#: tiramisu/option.py:937
msgid "invalid IP {0} ({1}) with netmask {2}"
msgstr ""
#: tiramisu/option.py:948
msgid "invalid broadcast address {0}"
#: tiramisu/option.py:939
msgid "invalid network {0} ({1}) with netmask {2}"
msgstr ""
#: tiramisu/option.py:952
msgid "invalid len for vals"
#: tiramisu/option.py:953
msgid "invalid broadcast address"
msgstr ""
#: tiramisu/option.py:957
msgid "invalid len for vals"
msgstr ""
#: tiramisu/option.py:962
msgid "invalid broadcast {0} ({1}) with network {2} ({3}) and netmask {4} ({5})"
msgstr ""
#: tiramisu/option.py:979
#: tiramisu/option.py:984
msgid "unknown type_ {0} for hostname"
msgstr ""
#: tiramisu/option.py:982
#: tiramisu/option.py:987
msgid "allow_ip must be a boolean"
msgstr ""
#: tiramisu/option.py:1012
msgid "invalid value for {0}, must have dot"
#: tiramisu/option.py:989
msgid "allow_without_dot must be a boolean"
msgstr ""
#: tiramisu/option.py:1015
msgid "invalid domainname's length for {0} (max {1})"
#: tiramisu/option.py:1028
msgid "invalid domainname, must have dot"
msgstr ""
#: tiramisu/option.py:1018
msgid "invalid domainname's length for {0} (min 2)"
#: tiramisu/option.py:1030
msgid "invalid domainname's length (max 255)"
msgstr ""
#: tiramisu/option.py:1022
#: tiramisu/option.py:1032
msgid "invalid domainname's length (min 2)"
msgstr ""
#: tiramisu/option.py:1034
msgid "invalid domainname"
msgstr ""
#: tiramisu/option.py:1049
#: tiramisu/option.py:1047
msgid "invalid email address, should contains one @"
msgstr ""
#: tiramisu/option.py:1050
msgid "invalid username in email address"
msgstr ""
#: tiramisu/option.py:1063
msgid "invalid url, should start with http:// or https://"
msgstr ""
#: tiramisu/option.py:1082
msgid "invalid url, port must be an between 0 and 65536"
msgstr ""
#: tiramisu/option.py:1088
msgid "invalid url, should ends with filename"
msgstr ""
#: tiramisu/option.py:1099
msgid "invalid filename"
msgstr ""
#: tiramisu/option.py:1126
msgid "duplicate option name: {0}"
msgstr ""
#: tiramisu/option.py:1067
#: tiramisu/option.py:1144
msgid "unknown Option {0} in OptionDescription {1}"
msgstr ""
#: tiramisu/option.py:1118
#: tiramisu/option.py:1195
msgid "duplicate option: {0}"
msgstr ""
#: tiramisu/option.py:1148
#: tiramisu/option.py:1225
msgid "consistency with option {0} which is not in Config"
msgstr ""
#: tiramisu/option.py:1156
#: tiramisu/option.py:1233
msgid "no option for path {0}"
msgstr ""
#: tiramisu/option.py:1162
#: tiramisu/option.py:1239
msgid "no option {0} found"
msgstr ""
#: tiramisu/option.py:1172
#: tiramisu/option.py:1249
msgid "cannot change group_type if already set (old {0}, new {1})"
msgstr ""
#: tiramisu/option.py:1185
#: tiramisu/option.py:1261
msgid "master group {0} shall not have a subgroup"
msgstr ""
#: tiramisu/option.py:1188
#: tiramisu/option.py:1264
msgid "master group {0} shall not have a symlinkoption"
msgstr ""
#: tiramisu/option.py:1191
#: tiramisu/option.py:1267
msgid "not allowed option {0} in group {1}: this option is not a multi"
msgstr ""
#: tiramisu/option.py:1202
#: tiramisu/option.py:1277
msgid "master group with wrong master name for {0}"
msgstr ""
#: tiramisu/option.py:1211
msgid "no child has same nom has master group for: {0}"
#: tiramisu/option.py:1285
msgid "callback of master's option shall not refered a slave's ones"
msgstr ""
#: tiramisu/option.py:1214
#: tiramisu/option.py:1293
msgid "group_type: {0} not allowed"
msgstr ""
#: tiramisu/option.py:1306
#: tiramisu/option.py:1385
msgid "malformed requirements type for option: {0}, must be a dict"
msgstr ""
#: tiramisu/option.py:1323
#: tiramisu/option.py:1402
msgid "malformed requirements for option: {0} require must have option, expected and action keys"
msgstr ""
#: tiramisu/option.py:1328
#: tiramisu/option.py:1407
msgid "malformed requirements for option: {0} inverse must be boolean"
msgstr ""
#: tiramisu/option.py:1332
#: tiramisu/option.py:1411
msgid "malformed requirements for option: {0} transitive must be boolean"
msgstr ""
#: tiramisu/option.py:1336
#: tiramisu/option.py:1415
msgid "malformed requirements for option: {0} same_action must be boolean"
msgstr ""
#: tiramisu/option.py:1340
#: tiramisu/option.py:1419
msgid "malformed requirements must be an option in option {0}"
msgstr ""
#: tiramisu/option.py:1343
#: tiramisu/option.py:1422
msgid "malformed requirements option {0} should not be a multi"
msgstr ""
#: tiramisu/option.py:1349
#: tiramisu/option.py:1428
msgid "malformed requirements second argument must be valid for option {0}: {1}"
msgstr ""
#: tiramisu/option.py:1354
#: tiramisu/option.py:1433
msgid "inconsistency in action types for option: {0} action: {1}"
msgstr ""
#: tiramisu/option.py:1379
#: tiramisu/option.py:1458
msgid "{0} should be a function"
msgstr ""
#: tiramisu/option.py:1382
#: tiramisu/option.py:1461
msgid "{0}_params should be a dict"
msgstr ""
#: tiramisu/option.py:1385
#: tiramisu/option.py:1464
msgid "{0}_params with key {1} should not have length different to 1"
msgstr ""
#: tiramisu/option.py:1389
#: tiramisu/option.py:1468
msgid "{0}_params should be tuple for key \"{1}\""
msgstr ""
#: tiramisu/option.py:1395
#: tiramisu/option.py:1474
msgid "validator not support tuple"
msgstr ""
#: tiramisu/option.py:1398
#: tiramisu/option.py:1477
msgid "{0}_params should have an option not a {0} for first argument"
msgstr ""
#: tiramisu/option.py:1402
#: tiramisu/option.py:1481
msgid "{0}_params should have a boolean not a {0} for second argument"
msgstr ""
#: tiramisu/setting.py:111
#: tiramisu/setting.py:116
msgid "can't rebind {0}"
msgstr ""
#: tiramisu/setting.py:116
#: tiramisu/setting.py:121
msgid "can't unbind {0}"
msgstr ""
#: tiramisu/setting.py:254
#: tiramisu/setting.py:272
msgid "cannot append {0} property for option {1}: this property is calculated"
msgstr ""
#: tiramisu/setting.py:317
#: tiramisu/setting.py:363
msgid "opt and all_properties must not be set together in reset"
msgstr ""
#: tiramisu/setting.py:332
#: tiramisu/setting.py:378
msgid "if opt is not None, path should not be None in _getproperties"
msgstr ""
#: tiramisu/setting.py:435
#: tiramisu/setting.py:483
msgid "cannot change the value for option {0} this option is frozen"
msgstr ""
#: tiramisu/setting.py:441
#: tiramisu/setting.py:489
msgid "trying to access to an option named: {0} with properties {1}"
msgstr ""
#: tiramisu/setting.py:459
#: tiramisu/setting.py:507
msgid "permissive must be a tuple"
msgstr ""
#: tiramisu/setting.py:466 tiramisu/value.py:299
#: tiramisu/setting.py:514 tiramisu/value.py:315
msgid "invalid generic owner {0}"
msgstr ""
#: tiramisu/setting.py:553
#: tiramisu/setting.py:602
msgid "malformed requirements imbrication detected for option: '{0}' with requirement on: '{1}'"
msgstr ""
#: tiramisu/setting.py:565
#: tiramisu/setting.py:613
msgid "option '{0}' has requirement's property error: {1} {2}"
msgstr ""
#: tiramisu/storage/__init__.py:47
#: tiramisu/storage/__init__.py:52
msgid "storage_type is already set, cannot rebind it"
msgstr ""
#: tiramisu/storage/__init__.py:81
#: tiramisu/storage/__init__.py:86
msgid "option {0} not already exists in storage {1}"
msgstr ""
#: tiramisu/storage/dictionary/storage.py:37
#: tiramisu/storage/dictionary/storage.py:39
msgid "dictionary storage cannot delete session"
msgstr ""
#: tiramisu/storage/dictionary/storage.py:48
#: tiramisu/storage/dictionary/storage.py:50
msgid "session already used"
msgstr ""
#: tiramisu/storage/dictionary/storage.py:50
#: tiramisu/storage/dictionary/storage.py:52
msgid "a dictionary cannot be persistent"
msgstr ""
#: tiramisu/value.py:306
#: tiramisu/value.py:322
msgid "no value for {0} cannot change owner to {1}"
msgstr ""
#: tiramisu/value.py:414
#: tiramisu/value.py:442
msgid "invalid len for the slave: {0} which has {1} as master"
msgstr ""
#: tiramisu/value.py:438
#: tiramisu/value.py:466
msgid "invalid len for the master: {0} which has {1} as slave with greater len"
msgstr ""
#: tiramisu/value.py:468
#: tiramisu/value.py:496
msgid "cannot append a value on a multi option {0} which is a slave"
msgstr ""
#: tiramisu/value.py:505
#: tiramisu/value.py:535
msgid "cannot sort multi option {0} if master or slave"
msgstr ""
#: tiramisu/value.py:509
#: tiramisu/value.py:539
msgid "cmp is not permitted in python v3 or greater"
msgstr ""
#: tiramisu/value.py:518
#: tiramisu/value.py:548
msgid "cannot reverse multi option {0} if master or slave"
msgstr ""
#: tiramisu/value.py:526
#: tiramisu/value.py:556
msgid "cannot insert multi option {0} if master or slave"
msgstr ""
#: tiramisu/value.py:534
#: tiramisu/value.py:564
msgid "cannot extend multi option {0} if master or slave"
msgstr ""
#: tiramisu/value.py:562
#: tiramisu/value.py:575
msgid "invalid value {0} for option {1}: {2}"
msgstr ""
#: tiramisu/value.py:593
msgid "cannot pop a value on a multi option {0} which is a slave"
msgstr ""