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.option.OptionDescription` is the shema, the option's structure
- :class:`tiramisu.config.Config` which is the whole configuration entry point - :class:`tiramisu.config.Config` which is the whole configuration entry point
.. image:: config.png
Accessing the `Option`'s 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`), The `Option` objects (in this case the :class:`~tiramisu.option.BoolOption`),
are organized into a tree into nested are organized into a tree into nested
:class:`~tiramisu.option.OptionDescription` objects. Every option has a name, :class:`~tiramisu.option.OptionDescription` objects.
as does every option group. The parts of the full name of the option are
separated by dots: e.g. ``cfg.optgroup.optname``. .. 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 Let's make the protocol of accessing a `Config`'s attribute explicit
(because explicit is better than implicit): (because explicit is better than implicit):
@ -363,6 +365,10 @@ read/write or read only mode::
>>> print c.od1.var3 >>> print c.od1.var3
value 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 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:: :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.config import Config
from tiramisu.option import IntOption, FloatOption, StrOption, ChoiceOption, \ from tiramisu.option import IntOption, FloatOption, StrOption, ChoiceOption, \
BoolOption, UnicodeOption, OptionDescription BoolOption, UnicodeOption, OptionDescription
from tiramisu.error import ConflictError from tiramisu.error import ConflictError, ConfigError
def make_description(): def make_description():
@ -131,8 +131,10 @@ def test_cfgimpl_get_home_by_path():
config.bool = False config.bool = False
assert config.cfgimpl_get_home_by_path('gc.dummy')[1] == 'dummy' assert config.cfgimpl_get_home_by_path('gc.dummy')[1] == 'dummy'
assert config.cfgimpl_get_home_by_path('dummy')[1] == 'dummy' assert config.cfgimpl_get_home_by_path('dummy')[1] == 'dummy'
#assert config.getpaths(include_groups=False) == ['gc.name', 'gc.dummy', 'gc.float', 'bool', 'objspace', 'wantref', 'str', 'wantframework', 'int', 'boolop']
#assert config.getpaths(include_groups=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(): def test_information_config():
@ -142,6 +144,7 @@ def test_information_config():
config.impl_set_information('info', string) config.impl_set_information('info', string)
assert config.impl_get_information('info') == string assert config.impl_get_information('info') == string
raises(ValueError, "config.impl_get_information('noinfo')") raises(ValueError, "config.impl_get_information('noinfo')")
assert config.impl_get_information('noinfo', 'default') == 'default'
def test_config_impl_get_path_by_opt(): def test_config_impl_get_path_by_opt():
@ -149,8 +152,10 @@ def test_config_impl_get_path_by_opt():
config = Config(descr) config = Config(descr)
dummy = config.unwrap_from_path('gc.dummy') dummy = config.unwrap_from_path('gc.dummy')
boo = config.unwrap_from_path('bool') 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(boo) == 'bool'
assert config.cfgimpl_get_description().impl_get_path_by_opt(dummy) == 'gc.dummy' 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(): 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') 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('bool') == boo
assert config.cfgimpl_get_description().impl_get_opt_by_path('gc.dummy') == dummy 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(): def test_information_display():
@ -231,8 +237,60 @@ def test_duplicated_option():
#in different OptionDescription #in different OptionDescription
raises(ConflictError, "config = Config(root)") raises(ConflictError, "config = Config(root)")
def test_cannot_assign_value_to_option_description(): def test_cannot_assign_value_to_option_description():
descr = make_description() descr = make_description()
cfg = Config(descr) cfg = Config(descr)
raises(TypeError, "cfg.gc = 3") 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.config import Config
from tiramisu.option import IntOption, FloatOption, StrOption, ChoiceOption, \ from tiramisu.option import IntOption, FloatOption, StrOption, ChoiceOption, \
BoolOption, OptionDescription BoolOption, FilenameOption, OptionDescription
def make_description(): def make_description():
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref') gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
gcdummy = BoolOption('dummy', 'dummy', default=False) gcdummy = BoolOption('dummy', 'dummy', default=False)
prop = BoolOption('prop', '', properties=('disabled',))
prop2 = BoolOption('prop', '', properties=('hidden',))
objspaceoption = ChoiceOption('objspace', 'Object space', objspaceoption = ChoiceOption('objspace', 'Object space',
('std', 'thunk'), 'std') ('std', 'thunk'), 'std')
booloption = BoolOption('bool', 'Test boolean option', default=True) booloption = BoolOption('bool', 'Test boolean option', default=True)
booloption2 = BoolOption('bool', 'Test boolean option', default=False)
intoption = IntOption('int', 'Test int option', default=0) 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) floatoption = FloatOption('float', 'Test float option', default=2.3)
stroption = StrOption('str', 'Test string option', default="abc") stroption = StrOption('str', 'Test string option', default="abc")
boolop = BoolOption('boolop', 'Test boolean option op', default=True) boolop = BoolOption('boolop', 'Test boolean option op', default=True)
wantref_option = BoolOption('wantref', 'Tests', default=False) wantref_option = BoolOption('wantref', 'Tests', default=False)
wantframework_option = BoolOption('wantframework', 'Test', 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, descr = OptionDescription('tiramisu', '', [gcgroup, booloption, objspaceoption,
wantref_option, stroption, wantref_option, stroption,
wantframework_option, wantframework_option,
intoption, boolop]) intoption, boolop, floatoption2])
return descr return descr
@ -100,20 +105,40 @@ def test_find_in_config():
"finds option in config" "finds option in config"
descr = make_description() descr = make_description()
conf = Config(descr) conf = Config(descr)
conf.read_only()
assert conf.find(byname='dummy') == [conf.unwrap_from_path('gc.dummy')] 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='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(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_first(bytype=ChoiceOption) == conf.unwrap_from_path('gc.name')
assert conf.find(byvalue='ref') == [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_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 # combinaison of filters
assert conf.find(bytype=BoolOption, byname='dummy') == [conf.unwrap_from_path('gc.dummy')] 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_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(byvalue=False, byname='dummy') == [conf.unwrap_from_path('gc.dummy')]
assert conf.find_first(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 #subconfig
#assert conf.find_first(byattrs= dict(default=2.3)) == conf.unwrap_from_path('gc.float') assert conf.gc.find(byname='dummy') == [conf.unwrap_from_path('gc.dummy')]
#assert conf.find_first(byvalue=False, byname='dummy', byattrs=dict(default=False)) == 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(): def test_find_multi():
@ -137,3 +162,18 @@ def test_does_not_find_in_config():
descr = make_description() descr = make_description()
conf = Config(descr) conf = Config(descr)
raises(AttributeError, "conf.find(byname='IDontExist')") 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 py.test import raises
from tiramisu.config import Config from tiramisu.config import Config
from tiramisu.option import DomainnameOption, OptionDescription from tiramisu.option import DomainnameOption, EmailOption, URLOption, OptionDescription
def test_domainname(): def test_domainname():
d = DomainnameOption('d', '') d = DomainnameOption('d', '')
e = DomainnameOption('e', '', "toto.com") 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 = Config(od)
c.read_write() c.read_write()
c.d = 'toto.com' c.d = 'toto.com'
raises(ValueError, "c.d = 'toto'") raises(ValueError, "c.d = 'toto'")
c.d = 'toto3.com' c.d = 'toto3.com'
c.d = 'toto3.3la' raises(ValueError, "c.d = 'toto3.3la'")
raises(ValueError, "c.d = '3toto.com'") raises(ValueError, "c.d = '3toto.com'")
c.d = 'toto.co3' raises(ValueError, "c.d = 'toto.co3'")
raises(ValueError, "c.d = 'toto_super.com'") raises(ValueError, "c.d = 'toto_super.com'")
c.d = 'toto-.com' c.d = 'toto-.com'
raises(ValueError, "c.d = 'toto..com'")
#
c.f = 'toto.com'
c.f = 'toto'
def test_domainname_netbios(): def test_domainname_netbios():
@ -41,3 +46,33 @@ def test_domainname_hostname():
raises(ValueError, "c.d = 'toto.com'") raises(ValueError, "c.d = 'toto.com'")
c.d = 'toto' c.d = 'toto'
c.d = 'domainnametoolong' 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' c.b = '0.0.0.0'
raises(ValueError, "c.b = '255.255.255.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(): def test_ip_default():
a = IPOption('a', '', '88.88.88.88') 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 and to compare them
""" """
import autopath 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(): #def test_option_comparison():
@ -36,3 +41,60 @@ from tiramisu.option import BoolOption, IntOption
# assert dummy1 != dummy5 # assert dummy1 != dummy5
# assert dummy1 == dummy6 # assert dummy1 == dummy6
# assert dummy1 != dummy7 # 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): 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): def return_value(value=None):
@ -34,6 +40,10 @@ def return_value2(*args, **kwargs):
return value return value
def return_calc(i, j, k):
return i + j + k
def make_description(): def make_description():
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref') gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
gcdummy = BoolOption('dummy', 'dummy', default=False) gcdummy = BoolOption('dummy', 'dummy', default=False)
@ -93,83 +103,6 @@ def test_identical_paths():
raises(ConflictError, "make_description_duplicates()") 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(): def make_description_requires():
gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref') gcoption = ChoiceOption('name', 'GC name', ('ref', 'framework'), 'ref')
gcdummy = BoolOption('dummy', 'dummy', default=False) gcdummy = BoolOption('dummy', 'dummy', default=False)
@ -310,6 +243,19 @@ def test_callback():
assert cfg.val1 == 'val' 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(): def test_callback_value():
val1 = StrOption('val1', "", 'val') val1 = StrOption('val1', "", 'val')
val2 = StrOption('val2', "", callback=return_value, callback_params={'': ((val1, False),)}) val2 = StrOption('val2', "", callback=return_value, callback_params={'': ((val1, False),)})
@ -421,12 +367,15 @@ def test_callback_multi_value():
cfg.val1.append('new-val2') cfg.val1.append('new-val2')
assert cfg.val1 == ['new-val', 'new-val2'] assert cfg.val1 == ['new-val', 'new-val2']
assert cfg.val2 == ['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) del(cfg.val1)
assert cfg.val1 == ['val'] assert cfg.val1 == ['val']
assert cfg.val2 == ['val'] assert cfg.val2 == ['val']
assert cfg.val3 == ['yes'] assert cfg.val3 == ['yes']
assert cfg.val4 == ['val', 'yes'] assert cfg.val4 == ['val', 'yes']
cfg.val2.append('new')
assert cfg.val1 == ['val']
assert cfg.val2 == ['val', 'new']
def test_callback_multi_list(): def test_callback_multi_list():
@ -443,6 +392,14 @@ def test_callback_multi_list():
assert cfg.val1 == ['val', 'val'] 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(): def test_callback_master_and_slaves_master():
val1 = StrOption('val1', "", multi=True, callback=return_val) val1 = StrOption('val1', "", multi=True, callback=return_val)
val2 = StrOption('val2', "", multi=True) val2 = StrOption('val2', "", multi=True)
@ -452,7 +409,7 @@ def test_callback_master_and_slaves_master():
cfg = Config(maconfig) cfg = Config(maconfig)
cfg.read_write() cfg.read_write()
assert cfg.val1.val1 == ['val'] assert cfg.val1.val1 == ['val']
cfg.val1.val1.append(None) cfg.val1.val1.append()
assert cfg.val1.val1 == ['val', 'val'] assert cfg.val1.val1 == ['val', 'val']
assert cfg.val1.val2 == [None, None] assert cfg.val1.val2 == [None, None]
@ -467,7 +424,7 @@ def test_callback_master_and_slaves_master_list():
cfg.read_write() cfg.read_write()
assert cfg.val1.val1 == ['val', 'val'] assert cfg.val1.val1 == ['val', 'val']
assert cfg.val1.val2 == [None, None] 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.val1 == ['val', 'val', None]
assert cfg.val1.val2 == [None, None, None] assert cfg.val1.val2 == [None, None, None]
del(cfg.val1.val1) del(cfg.val1.val1)
@ -512,6 +469,66 @@ def test_callback_master_and_slaves_slave():
assert cfg.val1.val2 == ['val2', 'val2', 'val'] 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(): def test_callback_master_and_slaves_slave_list():
val1 = StrOption('val1', "", multi=True) val1 = StrOption('val1', "", multi=True)
val2 = StrOption('val2', "", multi=True, callback=return_list) 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',)}) val3 = StrOption('val3', "", multi=True, callback=return_value, callback_params={'': ('yes',)})
val4 = StrOption('val4', '', multi=True, default=['val10', 'val11']) val4 = StrOption('val4', '', multi=True, default=['val10', 'val11'])
val5 = StrOption('val5', "", multi=True, callback=return_value, callback_params={'': ((val4, False),)}) 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) interface1.impl_set_group_type(groups.master)
maconfig = OptionDescription('rootconfig', '', [interface1, val4]) maconfig = OptionDescription('rootconfig', '', [interface1, val4])
cfg = Config(maconfig) cfg = Config(maconfig)
@ -544,30 +562,35 @@ def test_callback_master_and_slaves_value():
assert cfg.val1.val2 == [] assert cfg.val1.val2 == []
assert cfg.val1.val3 == [] assert cfg.val1.val3 == []
assert cfg.val1.val5 == [] assert cfg.val1.val5 == []
assert cfg.val1.val6 == []
# #
cfg.val1.val1 = ['val1'] cfg.val1.val1 = ['val1']
assert cfg.val1.val1 == ['val1'] assert cfg.val1.val1 == ['val1']
assert cfg.val1.val2 == ['val1'] assert cfg.val1.val2 == ['val1']
assert cfg.val1.val3 == ['yes'] assert cfg.val1.val3 == ['yes']
assert cfg.val1.val5 == ['val10'] assert cfg.val1.val5 == ['val10']
assert cfg.val1.val6 == ['val10']
# #
cfg.val1.val1.append('val2') cfg.val1.val1.append('val2')
assert cfg.val1.val1 == ['val1', 'val2'] assert cfg.val1.val1 == ['val1', 'val2']
assert cfg.val1.val2 == ['val1', 'val2'] assert cfg.val1.val2 == ['val1', 'val2']
assert cfg.val1.val3 == ['yes', 'yes'] assert cfg.val1.val3 == ['yes', 'yes']
assert cfg.val1.val5 == ['val10', 'val11'] assert cfg.val1.val5 == ['val10', 'val11']
assert cfg.val1.val6 == ['val10', 'val11']
# #
cfg.val1.val1 = ['val1', 'val2', 'val3'] cfg.val1.val1 = ['val1', 'val2', 'val3']
assert cfg.val1.val1 == ['val1', 'val2', 'val3'] assert cfg.val1.val1 == ['val1', 'val2', 'val3']
assert cfg.val1.val2 == ['val1', 'val2', 'val3'] assert cfg.val1.val2 == ['val1', 'val2', 'val3']
assert cfg.val1.val3 == ['yes', 'yes', 'yes'] assert cfg.val1.val3 == ['yes', 'yes', 'yes']
assert cfg.val1.val5 == ['val10', 'val11', None] assert cfg.val1.val5 == ['val10', 'val11', None]
assert cfg.val1.val6 == ['val10', 'val11', None]
# #
cfg.val1.val1.pop(2) cfg.val1.val1.pop(2)
assert cfg.val1.val1 == ['val1', 'val2'] assert cfg.val1.val1 == ['val1', 'val2']
assert cfg.val1.val2 == ['val1', 'val2'] assert cfg.val1.val2 == ['val1', 'val2']
assert cfg.val1.val3 == ['yes', 'yes'] assert cfg.val1.val3 == ['yes', 'yes']
assert cfg.val1.val5 == ['val10', 'val11'] assert cfg.val1.val5 == ['val10', 'val11']
assert cfg.val1.val6 == ['val10', 'val11']
# #
cfg.val1.val2 = ['val2', 'val2'] cfg.val1.val2 = ['val2', 'val2']
cfg.val1.val3 = ['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.val2 == ['val2', 'val2']
assert cfg.val1.val3 == ['val2', 'val2'] assert cfg.val1.val3 == ['val2', 'val2']
assert cfg.val1.val5 == ['val2', 'val2'] assert cfg.val1.val5 == ['val2', 'val2']
assert cfg.val1.val6 == ['val2', 'val2']
# #
cfg.val1.val1.append('val3') cfg.val1.val1.append('val3')
assert cfg.val1.val2 == ['val2', 'val2', 'val3'] assert cfg.val1.val2 == ['val2', 'val2', 'val3']
assert cfg.val1.val3 == ['val2', 'val2', 'yes'] assert cfg.val1.val3 == ['val2', 'val2', 'yes']
assert cfg.val1.val5 == ['val2', 'val2', None] assert cfg.val1.val5 == ['val2', 'val2', None]
assert cfg.val1.val6 == ['val2', 'val2', None]
cfg.cfgimpl_get_settings().remove('cache') cfg.cfgimpl_get_settings().remove('cache')
cfg.val4 = ['val10', 'val11', 'val12'] cfg.val4 = ['val10', 'val11', 'val12']
#if value is already set, not updated ! #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.append('val3')
cfg.val1.val1 = ['val1', 'val2', 'val3'] cfg.val1.val1 = ['val1', 'val2', 'val3']
assert cfg.val1.val5 == ['val2', 'val2', 'val12'] 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(): def test_callback_hidden():
@ -653,7 +741,7 @@ def test_callback_multi_list_params():
maconfig = OptionDescription('rootconfig', '', [val1, oval2]) maconfig = OptionDescription('rootconfig', '', [val1, oval2])
cfg = Config(maconfig) cfg = Config(maconfig)
cfg.read_write() cfg.read_write()
assert cfg.val2.val2 == ['val', 'val', 'val', 'val'] assert cfg.val2.val2 == ['val', 'val']
def test_callback_multi_list_params_key(): def test_callback_multi_list_params_key():
@ -663,31 +751,4 @@ def test_callback_multi_list_params_key():
maconfig = OptionDescription('rootconfig', '', [val1, oval2]) maconfig = OptionDescription('rootconfig', '', [val1, oval2])
cfg = Config(maconfig) cfg = Config(maconfig)
cfg.read_write() cfg.read_write()
assert cfg.val2.val2 == ['val', 'val', 'val', 'val'] assert cfg.val2.val2 == ['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")

View File

@ -8,6 +8,17 @@ from tiramisu.option import IPOption, NetworkOption, NetmaskOption, IntOption,\
from tiramisu.error import ConfigError 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(): def test_consistency_not_equal():
a = IntOption('a', '') a = IntOption('a', '')
b = IntOption('b', '') b = IntOption('b', '')

View File

@ -5,7 +5,7 @@ from tiramisu.setting import owners
from tiramisu.config import Config from tiramisu.config import Config
from tiramisu.option import ChoiceOption, BoolOption, IntOption, FloatOption, \ from tiramisu.option import ChoiceOption, BoolOption, IntOption, FloatOption, \
StrOption, OptionDescription StrOption, OptionDescription
from tiramisu.error import ConfigError from tiramisu.error import ConfigError, ConstError
def make_description(): def make_description():
@ -52,6 +52,17 @@ def test_addowner():
assert cfg.getowner(gcdummy) == owners.gen_config 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(): def test_owner_is_not_a_string():
gcdummy = BoolOption('dummy', 'dummy', default=False) gcdummy = BoolOption('dummy', 'dummy', default=False)
descr = OptionDescription('tiramisu', '', [gcdummy]) descr = OptionDescription('tiramisu', '', [gcdummy])

View File

@ -75,6 +75,16 @@ def test_group_is_hidden():
prop = err.proptype prop = err.proptype
assert 'hidden' in prop 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(): def test_group_is_hidden_multi():
descr = make_description() descr = make_description()

View File

@ -6,6 +6,7 @@ from tiramisu.config import Config
from tiramisu.option import StrOption, OptionDescription from tiramisu.option import StrOption, OptionDescription
from tiramisu.setting import groups from tiramisu.setting import groups
from tiramisu.error import ValueWarning from tiramisu.error import ValueWarning
from tiramisu.i18n import _
def return_true(value, param=None): def return_true(value, param=None):
@ -87,7 +88,7 @@ def test_validator_warning():
cfg.opt2 = 'val' cfg.opt2 = 'val'
assert len(w) == 1 assert len(w) == 1
assert w[0].message.opt == opt2 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: with warnings.catch_warnings(record=True) as w:
cfg.opt3.append('val') cfg.opt3.append('val')
@ -97,7 +98,7 @@ def test_validator_warning():
cfg.opt3.append('val1') cfg.opt3.append('val1')
assert len(w) == 1 assert len(w) == 1
assert w[0].message.opt == opt3 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") raises(ValueError, "cfg.opt2 = 1")
# #
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings(record=True) as w:
@ -105,9 +106,9 @@ def test_validator_warning():
cfg.opt3.append('val') cfg.opt3.append('val')
assert len(w) == 2 assert len(w) == 2
assert w[0].message.opt == opt2 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 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(): def test_validator_warning_master_slave():
@ -127,29 +128,29 @@ def test_validator_warning_master_slave():
cfg.ip_admin_eth0.netmask_admin_eth0 = ['val1'] cfg.ip_admin_eth0.netmask_admin_eth0 = ['val1']
assert len(w) == 1 assert len(w) == 1
assert w[0].message.opt == netmask_admin_eth0 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: with warnings.catch_warnings(record=True) as w:
cfg.ip_admin_eth0.ip_admin_eth0 = ['val'] cfg.ip_admin_eth0.ip_admin_eth0 = ['val']
assert len(w) == 1 assert len(w) == 1
assert w[0].message.opt == ip_admin_eth0 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: with warnings.catch_warnings(record=True) as w:
cfg.ip_admin_eth0.ip_admin_eth0 = ['val', 'val1', 'val1'] cfg.ip_admin_eth0.ip_admin_eth0 = ['val', 'val1', 'val1']
assert len(w) == 1 assert len(w) == 1
assert w[0].message.opt == ip_admin_eth0 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: with warnings.catch_warnings(record=True) as w:
cfg.ip_admin_eth0.ip_admin_eth0 = ['val1', 'val', 'val1'] cfg.ip_admin_eth0.ip_admin_eth0 = ['val1', 'val', 'val1']
assert len(w) == 1 assert len(w) == 1
assert w[0].message.opt == ip_admin_eth0 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() warnings.resetwarnings()
with warnings.catch_warnings(record=True) as w: with warnings.catch_warnings(record=True) as w:
cfg.ip_admin_eth0.ip_admin_eth0 = ['val1', 'val1', 'val'] cfg.ip_admin_eth0.ip_admin_eth0 = ['val1', 'val1', 'val']
assert len(w) == 1 assert len(w) == 1
assert w[0].message.opt == ip_admin_eth0 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(): def make_description():
u1 = IntOption('u1', '', properties=('frozen', 'mandatory', 'disabled', )) 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(): def test_permissive():
@ -91,3 +92,108 @@ def test_invalid_permissive():
setting = config.cfgimpl_get_settings() setting = config.cfgimpl_get_settings()
config.read_write() config.read_write()
raises(TypeError, "setting.setpermissive(['frozen', 'disabled',])") 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'] 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(): def test_requires_same_action():
a = BoolOption('activate_service', '', True) a = BoolOption('activate_service', '', True)
b = BoolOption('activate_service_web', '', True, b = BoolOption('activate_service_web', '', True,
@ -504,6 +518,11 @@ def test_requires_requirement_append():
c.cfgimpl_get_settings()[b].append("test") 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(): def test_requires_recursive_path():
a = BoolOption('activate_service', '', True) a = BoolOption('activate_service', '', True)
b = IPOption('ip_address_service', '', b = IPOption('ip_address_service', '',

View File

@ -3,9 +3,10 @@ import autopath
from py.test import raises from py.test import raises
from tiramisu.config import Config, SubConfig 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, \ StrOption, SymLinkOption, UnicodeOption, IPOption, OptionDescription, \
PortOption, NetworkOption, NetmaskOption, DomainnameOption PortOption, NetworkOption, NetmaskOption, DomainnameOption, EmailOption, \
URLOption, FilenameOption
def test_slots_option(): def test_slots_option():
@ -35,6 +36,12 @@ def test_slots_option():
raises(AttributeError, "c.x = 1") raises(AttributeError, "c.x = 1")
c = DomainnameOption('a', '') c = DomainnameOption('a', '')
raises(AttributeError, "c.x = 1") 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(): def test_slots_option_readonly():
@ -49,7 +56,10 @@ def test_slots_option_readonly():
j = NetworkOption('j', '') j = NetworkOption('j', '')
k = NetmaskOption('k', '') k = NetmaskOption('k', '')
l = DomainnameOption('l', '') 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' a._requires = 'a'
b._requires = 'b' b._requires = 'b'
c._requires = 'c' c._requires = 'c'
@ -62,6 +72,9 @@ def test_slots_option_readonly():
k._requires = 'k' k._requires = 'k'
l._requires = 'l' l._requires = 'l'
m._requires = 'm' m._requires = 'm'
o._requires = 'o'
p._requires = 'p'
q._requires = 'q'
Config(m) Config(m)
raises(AttributeError, "a._requires = 'a'") raises(AttributeError, "a._requires = 'a'")
raises(AttributeError, "b._requires = 'b'") raises(AttributeError, "b._requires = 'b'")
@ -75,6 +88,9 @@ def test_slots_option_readonly():
raises(AttributeError, "k._requires = 'k'") raises(AttributeError, "k._requires = 'k'")
raises(AttributeError, "l._requires = 'l'") raises(AttributeError, "l._requires = 'l'")
raises(AttributeError, "m._requires = 'm'") 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(): def test_slots_option_readonly_name():
@ -90,7 +106,10 @@ def test_slots_option_readonly_name():
j = NetworkOption('j', '') j = NetworkOption('j', '')
k = NetmaskOption('k', '') k = NetmaskOption('k', '')
l = DomainnameOption('l', '') 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, "a._name = 'a'")
raises(AttributeError, "b._name = 'b'") raises(AttributeError, "b._name = 'b'")
raises(AttributeError, "c._name = 'c'") raises(AttributeError, "c._name = 'c'")
@ -104,6 +123,9 @@ def test_slots_option_readonly_name():
raises(AttributeError, "k._name = 'k'") raises(AttributeError, "k._name = 'k'")
raises(AttributeError, "l._name = 'l'") raises(AttributeError, "l._name = 'l'")
raises(AttributeError, "m._name = 'm'") raises(AttributeError, "m._name = 'm'")
raises(AttributeError, "o._name = 'o'")
raises(AttributeError, "p._name = 'p'")
raises(AttributeError, "q._name = 'q'")
def test_slots_description(): def test_slots_description():

View File

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

View File

@ -156,7 +156,15 @@ class SubConfig(object):
__repr__ = __str__ __repr__ = __str__
def _cfgimpl_get_context(self): 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): def cfgimpl_get_description(self):
if self._impl_descr is None: if self._impl_descr is None:
@ -250,7 +258,8 @@ class SubConfig(object):
force_properties=force_properties, force_properties=force_properties,
force_permissive=force_permissive) 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 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, return self._cfgimpl_get_context()._find(bytype, byname, byvalue,
first=False, first=False,
type_=type_, 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, 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 finds an option recursively in the config
@ -277,7 +286,8 @@ class SubConfig(object):
""" """
return self._cfgimpl_get_context()._find( return self._cfgimpl_get_context()._find(
bytype, byname, byvalue, first=True, type_=type_, 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', def _find(self, bytype, byname, byvalue, first, type_='option',
_subpath=None, check_properties=True, display_error=True): _subpath=None, check_properties=True, display_error=True):
@ -734,4 +744,6 @@ def mandatory_warnings(config):
except PropertiesOptionError as err: except PropertiesOptionError as err:
if err.proptype == ['mandatory']: if err.proptype == ['mandatory']:
yield path yield path
except ConfigError:
pass
config.cfgimpl_reset_cache(only=('values',)) 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): def valid_name(name):
"an option's name is a str and does not start with 'impl' or 'cfgimpl'" "an option's name is a str and does not start with 'impl' or 'cfgimpl'"
try: if not isinstance(name, str):
name = str(name)
except:
return False return False
if re.match(name_regexp, name) is None and not name.startswith('_') \ if re.match(name_regexp, name) is None and not name.startswith('_') \
and name not in forbidden_names \ and name not in forbidden_names \
@ -413,7 +411,7 @@ class Option(BaseOption):
else: else:
validator_params = {'': (val,)} validator_params = {'': (val,)}
# Raise ValueError if not valid # Raise ValueError if not valid
carry_out_calculation(self._name, config=context, carry_out_calculation(self, config=context,
callback=self._validator[0], callback=self._validator[0],
callback_params=validator_params) callback_params=validator_params)
@ -421,7 +419,11 @@ class Option(BaseOption):
if _value is None: if _value is None:
return return
# option validation # 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: try:
# valid with self._validator # valid with self._validator
val_validator(_value) val_validator(_value)
@ -430,8 +432,8 @@ class Option(BaseOption):
descr._valid_consistency(self, _value, context, _index) descr._valid_consistency(self, _value, context, _index)
self._second_level_validation(_value) self._second_level_validation(_value)
except ValueError as err: except ValueError as err:
msg = _("invalid value {0} for option {1}: {2}").format( msg = _("invalid value for option {0}: {1}").format(
_value, self._name, err) self._name, err)
if self._warnings_only: if self._warnings_only:
warnings.warn_explicit(ValueWarning(msg, self), warnings.warn_explicit(ValueWarning(msg, self),
ValueWarning, ValueWarning,
@ -447,17 +449,13 @@ class Option(BaseOption):
do_validation(value, force_index) do_validation(value, force_index)
else: else:
if not isinstance(value, list): if not isinstance(value, list):
raise ValueError(_("which must be a list").format(value, raise ValueError(_("invalid value {0} for option {1} which must be a list").format(value, self._name))
self._name))
for index, val in enumerate(value): for index, val in enumerate(value):
do_validation(val, index) do_validation(val, index)
def impl_getdefault(self, default_multi=False): def impl_getdefault(self):
"accessing the default value" "accessing the default value"
if not default_multi or not self.impl_is_multi(): return self._default
return self._default
else:
return self.getdefault_multi()
def impl_getdefault_multi(self): def impl_getdefault_multi(self):
"accessing the default value for a multi" "accessing the default value for a multi"
@ -677,7 +675,7 @@ class BoolOption(Option):
def _validate(self, value): def _validate(self, value):
if not isinstance(value, bool): if not isinstance(value, bool):
raise ValueError(_('value must be a boolean')) raise ValueError(_('invalid boolean'))
class IntOption(Option): class IntOption(Option):
@ -687,7 +685,7 @@ class IntOption(Option):
def _validate(self, value): def _validate(self, value):
if not isinstance(value, int): if not isinstance(value, int):
raise ValueError(_('value must be an integer')) raise ValueError(_('invalid integer'))
class FloatOption(Option): class FloatOption(Option):
@ -697,7 +695,7 @@ class FloatOption(Option):
def _validate(self, value): def _validate(self, value):
if not isinstance(value, float): if not isinstance(value, float):
raise ValueError(_('value must be a float')) raise ValueError(_('invalid float'))
class StrOption(Option): class StrOption(Option):
@ -707,12 +705,11 @@ class StrOption(Option):
def _validate(self, value): def _validate(self, value):
if not isinstance(value, str): if not isinstance(value, str):
raise ValueError(_('value must be a string, not ' raise ValueError(_('invalid string'))
'{0}').format(type(value)))
if sys.version_info[0] >= 3: 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): class UnicodeOption(StrOption):
__slots__ = tuple() __slots__ = tuple()
pass pass
@ -725,7 +722,7 @@ else:
def _validate(self, value): def _validate(self, value):
if not isinstance(value, unicode): if not isinstance(value, unicode):
raise ValueError(_('value must be an unicode')) raise ValueError(_('invalid unicode'))
class SymLinkOption(BaseOption): class SymLinkOption(BaseOption):
@ -783,17 +780,23 @@ class IPOption(Option):
warnings_only=warnings_only) warnings_only=warnings_only)
def _validate(self, value): 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: try:
IP('{0}/32'.format(value)) IP('{0}/32'.format(value))
except ValueError: except ValueError:
raise ValueError(_('invalid IP {0}').format(self._name)) raise ValueError(_('invalid IP'))
def _second_level_validation(self, value): def _second_level_validation(self, value):
ip = IP('{0}/32'.format(value)) ip = IP('{0}/32'.format(value))
if not self._allow_reserved and ip.iptype() == 'RESERVED': 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': 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): class PortOption(Option):
@ -853,16 +856,17 @@ class PortOption(Option):
if self._allow_range and ":" in str(value): if self._allow_range and ":" in str(value):
value = str(value).split(':') value = str(value).split(':')
if len(value) != 2: 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]: 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') ' smaller than the second one')
else: else:
value = [value] value = [value]
for val in value: for val in value:
if not self._min_value <= int(val) <= self._max_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)) ''.format(self._min_value, self._max_value))
@ -875,12 +879,12 @@ class NetworkOption(Option):
try: try:
IP(value) IP(value)
except ValueError: except ValueError:
raise ValueError(_('invalid network address {0}').format(self._name)) raise ValueError(_('invalid network address'))
def _second_level_validation(self, value): def _second_level_validation(self, value):
ip = IP(value) ip = IP(value)
if ip.iptype() == 'RESERVED': 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): class NetmaskOption(Option):
@ -892,7 +896,7 @@ class NetmaskOption(Option):
try: try:
IP('0.0.0.0/{0}'.format(value)) IP('0.0.0.0/{0}'.format(value))
except ValueError: except ValueError:
raise ValueError(_('invalid netmask address {0}').format(self._name)) raise ValueError(_('invalid netmask address'))
def _cons_network_netmask(self, opts, vals): def _cons_network_netmask(self, opts, vals):
#opts must be (netmask, network) options #opts must be (netmask, network) options
@ -921,21 +925,21 @@ class NetmaskOption(Option):
except ValueError: except ValueError:
if not make_net: if not make_net:
msg = _("invalid network {0} ({1}) " msg = _("invalid network {0} ({1}) "
"with netmask {2} ({3})," "with netmask {2},"
" this network is an IP") " this network is an IP")
else: else:
if make_net: 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") " this IP is a network")
except ValueError: except ValueError:
if make_net: if make_net:
msg = _("invalid IP {0} ({1}) with netmask {2} ({3})") msg = _('invalid IP {0} ({1}) with netmask {2}')
else: else:
msg = _("invalid network {0} ({1}) with netmask {2} ({3})") msg = _('invalid network {0} ({1}) with netmask {2}')
if msg is not None: if msg is not None:
raise ValueError(msg.format(val_ipnetwork, opts[1]._name, raise ValueError(msg.format(val_ipnetwork, opts[1]._name,
val_netmask, self._name)) val_netmask))
class BroadcastOption(Option): class BroadcastOption(Option):
@ -946,7 +950,7 @@ class BroadcastOption(Option):
try: try:
IP('{0}/32'.format(value)) IP('{0}/32'.format(value))
except ValueError: except ValueError:
raise ValueError(_('invalid broadcast address {0}').format(self._name)) raise ValueError(_('invalid broadcast address'))
def _cons_broadcast(self, opts, vals): def _cons_broadcast(self, opts, vals):
if len(vals) != 3: if len(vals) != 3:
@ -968,20 +972,39 @@ class DomainnameOption(Option):
domainname: domainname:
fqdn: with tld, not supported yet fqdn: with tld, not supported yet
""" """
__slots__ = ('_type', '_allow_ip') __slots__ = ('_type', '_allow_ip', '_allow_without_dot', '_domain_re')
_opt_type = 'domainname' _opt_type = 'domainname'
def __init__(self, name, doc, default=None, default_multi=None, def __init__(self, name, doc, default=None, default_multi=None,
requires=None, multi=False, callback=None, requires=None, multi=False, callback=None,
callback_params=None, validator=None, validator_params=None, callback_params=None, validator=None, validator_params=None,
properties=None, allow_ip=False, type_='domainname', properties=None, allow_ip=False, type_='domainname',
warnings_only=False): warnings_only=False, allow_without_dot=False):
if type_ not in ['netbios', 'hostname', 'domainname']: if type_ not in ['netbios', 'hostname', 'domainname']:
raise ValueError(_('unknown type_ {0} for hostname').format(type_)) raise ValueError(_('unknown type_ {0} for hostname').format(type_))
self._type = type_ self._type = type_
if allow_ip not in [True, False]: if allow_ip not in [True, False]:
raise ValueError(_('allow_ip must be a boolean')) 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_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, super(DomainnameOption, self).__init__(name, doc, default=default,
default_multi=default_multi, default_multi=default_multi,
callback=callback, callback=callback,
@ -1000,29 +1023,82 @@ class DomainnameOption(Option):
return return
except ValueError: except ValueError:
pass pass
if self._type == 'netbios': if self._type == 'domainname' and not self._allow_without_dot and \
length = 15 '.' not in value:
extrachar = '' raise ValueError(_("invalid domainname, must have dot"))
elif self._type == 'hostname': if len(value) > 255:
length = 63 raise ValueError(_("invalid domainname's length (max 255)"))
extrachar = '' if len(value) < 2:
elif self._type == 'domainname': raise ValueError(_("invalid domainname's length (min 2)"))
length = 255 if not self._domain_re.search(value):
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:
raise ValueError(_('invalid domainname')) 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): class OptionDescription(BaseOption):
"""Config's schema (organisation, group) and container of Options """Config's schema (organisation, group) and container of Options
The `OptionsDescription` objects lives in the `tiramisu.config.Config`. The `OptionsDescription` objects lives in the `tiramisu.config.Config`.
@ -1177,7 +1253,6 @@ class OptionDescription(BaseOption):
self._group_type = group_type self._group_type = group_type
if isinstance(group_type, groups.MasterGroupType): if isinstance(group_type, groups.MasterGroupType):
#if master (same name has group) is set #if master (same name has group) is set
identical_master_child_name = False
#for collect all slaves #for collect all slaves
slaves = [] slaves = []
master = None master = None
@ -1194,7 +1269,6 @@ class OptionDescription(BaseOption):
": this option is not a multi" ": this option is not a multi"
"").format(child._name, self._name)) "").format(child._name, self._name))
if child._name == self._name: if child._name == self._name:
identical_master_child_name = True
child._multitype = multitypes.master child._multitype = multitypes.master
master = child master = child
else: else:
@ -1203,14 +1277,18 @@ class OptionDescription(BaseOption):
raise ValueError(_('master group with wrong' raise ValueError(_('master group with wrong'
' master name for {0}' ' master name for {0}'
).format(self._name)) ).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) master._master_slaves = tuple(slaves)
for child in self.impl_getchildren(): for child in self.impl_getchildren():
if child != master: if child != master:
child._master_slaves = master child._master_slaves = master
child._multitype = multitypes.slave child._multitype = multitypes.slave
if not identical_master_child_name:
raise ValueError(_("no child has same nom has master group"
" for: {0}").format(self._name))
else: else:
raise ValueError(_('group_type: {0}' raise ValueError(_('group_type: {0}'
' not allowed').format(group_type)) ' not allowed').format(group_type))

View File

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

View File

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

View File

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

View File

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

View File

@ -1,105 +1,105 @@
msgid "" msgid ""
msgstr "" msgstr ""
"Project-Id-Version: \n" "Project-Id-Version: Tiramisu\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: \n"
"Last-Translator: Emmanuel Garette <egarette@cadoles.com>\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" "MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n" "Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.5.4\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 "" msgid ""
"unable to carry out a calculation, option {0} has properties: {1} for: {2}" "unable to carry out a calculation, option {0} has properties: {1} for: {2}"
msgstr "" msgstr ""
"impossible d'effectuer le calcul, l'option {0} a les propriétés : {1} pour : " "impossible d'effectuer le calcul, l'option {0} a les propriétés : {1} pour : "
"{2}" "{2}"
#: tiramisu/autolib.py:153 #: tiramisu/config.py:52
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
msgid "descr must be an optiondescription, not {0}" msgid "descr must be an optiondescription, not {0}"
msgstr "descr doit être une optiondescription pas un {0}" msgstr "descr doit être une optiondescription pas un {0}"
#: tiramisu/config.py:126 #: tiramisu/config.py:127
msgid "unknown group_type: {0}" msgid "unknown group_type: {0}"
msgstr "group_type inconnu: {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 "" msgid ""
"no option description found for this config (may be metaconfig without meta)" "no option description found for this config (may be metaconfig without meta)"
msgstr "" msgstr ""
"pas d'option description trouvé pour cette config (peut être une metaconfig " "pas d'option description trouvé pour cette config (peut être une metaconfig "
"sans meta)" "sans meta)"
#: tiramisu/config.py:188 #: tiramisu/config.py:197
msgid "can't assign to an OptionDescription" msgid "can't assign to an OptionDescription"
msgstr "ne peut pas attribuer une valeur à une 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" msgid "unknown type_ type {0}for _find"
msgstr "type_ type {0} pour _find inconnu" msgstr "type_ type {0} pour _find inconnu"
#: tiramisu/config.py:358 #: tiramisu/config.py:369
msgid "no option found in config with these criteria" msgid "no option found in config with these criteria"
msgstr "aucune option trouvée dans la config avec ces critères" 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" msgid "make_dict can't filtering with value without option"
msgstr "make_dict ne peut filtrer sur une valeur mais sans 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}" msgid "unexpected path {0}, should start with {1}"
msgstr "chemin imprévu {0}, devrait commencer par {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}" msgid "opt in getowner must be an option not {0}"
msgstr "opt dans getowner doit être une option pas {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" msgid "invalid name: {0} for option"
msgstr "nom invalide : {0} pour l'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" msgid "invalid properties type {0} for {1}, must be a tuple"
msgstr "type des properties invalide {0} pour {1}, doit être un 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" msgid "'{0}' ({1}) object attribute '{2}' is read-only"
msgstr "l'attribut {2} de l'objet '{0}' ({1}) est en lecture seule" 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}" msgid "information's item not found: {0}"
msgstr "aucune config spécifiée alors que c'est nécessaire" 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" msgid "cannot serialize Option, only in OptionDescription"
msgstr "ne peut serialiser une Option, seulement via une 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}" msgid "a default_multi is set whereas multi is False in option: {0}"
msgstr "" msgstr ""
"une default_multi est renseignée alors que multi est False dans l'option : " "une default_multi est renseignée alors que multi est False dans l'option : "
"{0}" "{0}"
#: tiramisu/option.py:313 #: tiramisu/option.py:312
msgid "invalid default_multi value {0} for option {1}: {2}" msgid "invalid default_multi value {0} for option {1}: {2}"
msgstr "la valeur default_multi est invalide {0} pour l'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" 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" 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 "" msgid ""
"params defined for a callback function but no callback defined yet for " "params defined for a callback function but no callback defined yet for "
"option {0}" "option {0}"
@ -107,221 +107,251 @@ msgstr ""
"params définis pour une fonction callback mais par de callback encore " "params définis pour une fonction callback mais par de callback encore "
"définis pour l'option {0}" "définis pour l'option {0}"
#: tiramisu/option.py:360 #: tiramisu/option.py:359
msgid "option not in all_cons_opts" msgid "option not in all_cons_opts"
msgstr "option non présentante dans all_cons_opts" msgstr "option non présentante dans all_cons_opts"
#: tiramisu/option.py:432 tiramisu/value.py:545 #: tiramisu/option.py:425 tiramisu/option.py:435
msgid "invalid value {0} for option {1}: {2}" msgid "invalid value for option {0}: {1}"
msgstr "valeur invalide {0} pour l'option {1} : {2}" msgstr "valeur invalide pour l'option {0} : {1}"
#: tiramisu/option.py:449 #: tiramisu/option.py:452
msgid "which must be a list" msgid "invalid value {0} for option {1} which must be a list"
msgstr "lequel doit être une liste" 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" msgid "consistency should be set with an option"
msgstr "consistency doit être configuré avec une option" msgstr "consistency doit être configuré avec une option"
#: tiramisu/option.py:511 #: tiramisu/option.py:510
msgid "cannot add consistency with itself" msgid "cannot add consistency with itself"
msgstr "ne peut ajouter une consistency avec lui même" 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" msgid "every options in consistency should be multi or none"
msgstr "" msgstr ""
"toutes les options d'une consistency devrait être multi ou ne pas l'être" "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}" msgid "same value for {0} and {1}"
msgstr "même valeur pour {0} et {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}" msgid "values must be a tuple for {0}"
msgstr "values doit être un tuple pour {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}" msgid "open_values must be a boolean for {0}"
msgstr "open_values doit être un booléen pour {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" msgid "value {0} is not permitted, only {1} is allowed"
msgstr "valeur {0} n'est pas permis, seules {1} sont autorisées" msgstr "valeur {0} n'est pas permis, seules {1} sont autorisées"
#: tiramisu/option.py:679 #: tiramisu/option.py:678
msgid "value must be a boolean" msgid "invalid boolean"
msgstr "valeur doit être un booléen" msgstr "booléen invalide"
#: tiramisu/option.py:689 #: tiramisu/option.py:688
msgid "value must be an integer" msgid "invalid integer"
msgstr "valeur doit être un nombre entier" msgstr "nombre invalide"
#: tiramisu/option.py:699 #: tiramisu/option.py:698
msgid "value must be a float" msgid "invalid float"
msgstr "valeur doit être un nombre flottant" msgstr "invalide nombre flottan"
#: tiramisu/option.py:709 #: tiramisu/option.py:708
msgid "value must be a string, not {0}" msgid "invalid string"
msgstr "valeur doit être une chaîne, pas {0}" msgstr "invalide caractère"
#: tiramisu/option.py:727 #: tiramisu/option.py:725
msgid "value must be an unicode" msgid "invalid unicode"
msgstr "valeur doit être une valeur unicode" msgstr "invalide unicode"
#: tiramisu/option.py:739 #: tiramisu/option.py:737
msgid "malformed symlinkoption must be an option for symlink {0}" msgid "malformed symlinkoption must be an option for symlink {0}"
msgstr "symlinkoption mal formé, doit être une option pour symlink {0}" msgstr "symlinkoption mal formé, doit être une option pour symlink {0}"
#: tiramisu/option.py:788 #: tiramisu/option.py:787 tiramisu/option.py:792
msgid "invalid IP {0}" msgid "invalid IP"
msgstr "adresse IP invalide {0}" msgstr "adresse IP invalide"
#: tiramisu/option.py:793 #: tiramisu/option.py:797
msgid "IP mustn't not be in reserved class" msgid "invalid IP, mustn't not be in reserved class"
msgstr "IP ne doit pas être d'une classe reservée" msgstr "adresse IP invalide, ne doit pas être d'une classe reservée"
#: tiramisu/option.py:795 #: tiramisu/option.py:799
msgid "IP must be in private class" msgid "invalid IP, must be in private class"
msgstr "IP doit être dans la classe privée" msgstr "adresse IP invalide, doit être dans la classe privée"
#: tiramisu/option.py:833 #: tiramisu/option.py:837
msgid "inconsistency in allowed range" msgid "inconsistency in allowed range"
msgstr "inconsistence dans la plage autorisée" msgstr "inconsistence dans la plage autorisée"
#: tiramisu/option.py:838 #: tiramisu/option.py:842
msgid "max value is empty" msgid "max value is empty"
msgstr "la valeur maximum est vide" 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 #: tiramisu/option.py:882
msgid "network shall not be in reserved class" msgid "invalid network address"
msgstr "le réseau ne doit pas être dans la classe reservée" msgstr "adresse réseau invalide"
#: tiramisu/option.py:894 #: tiramisu/option.py:887
msgid "invalid netmask address {0}" msgid "invalid network address, must not be in reserved class"
msgstr "masque de sous-réseau invalide {0}" 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" msgid "invalid len for opts"
msgstr "longueur invalide pour 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 #: 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 "IP invalide {0} ({1}) avec masque {2} ({3}), cette IP est un réseau" msgstr "réseau invalide {0} ({1}) avec masque {2}, ce réseau est une IP"
#: tiramisu/option.py:932 #: 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 "IP invalide {0} ({1}) avec masque {2} ({3})" msgstr "IP invalide {0} ({1}) avec masque {2}, cette IP est un réseau"
#: tiramisu/option.py:934 #: tiramisu/option.py:937
msgid "invalid network {0} ({1}) with netmask {2} ({3})" msgid "invalid IP {0} ({1}) with netmask {2}"
msgstr "réseau invalide {0} ({1}) avec masque {2} ({3})" msgstr "IP invalide {0} ({1}) avec masque {2}"
#: tiramisu/option.py:948 #: tiramisu/option.py:939
msgid "invalid broadcast address {0}" msgid "invalid network {0} ({1}) with netmask {2}"
msgstr "adresse de broadcast invalide {0}" 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" msgid "invalid len for vals"
msgstr "longueur invalide pour vals" msgstr "longueur invalide pour vals"
#: tiramisu/option.py:957 #: tiramisu/option.py:962
msgid "" msgid ""
"invalid broadcast {0} ({1}) with network {2} ({3}) and netmask {4} ({5})" "invalid broadcast {0} ({1}) with network {2} ({3}) and netmask {4} ({5})"
msgstr "" msgstr ""
"Broadcast invalide {0} ({1}) avec le réseau {2} ({3}) et le masque {4} ({5})" "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" msgid "unknown type_ {0} for hostname"
msgstr "type_ inconnu {0} pour le nom d'hôte" 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" msgid "allow_ip must be a boolean"
msgstr "allow_ip doit être un booléen" msgstr "allow_ip doit être un booléen"
#: tiramisu/option.py:1012 #: tiramisu/option.py:989
msgid "invalid value for {0}, must have dot" msgid "allow_without_dot must be a boolean"
msgstr "valeur invalide pour {0}, doit avoir un point" msgstr "allow_without_dot doit être un booléen"
#: tiramisu/option.py:1015 #: tiramisu/option.py:1028
msgid "invalid domainname's length for {0} (max {1})" msgid "invalid domainname, must have dot"
msgstr "longueur du nom de domaine invalide pour {0} (maximum {1})" msgstr "nom de domaine invalide, doit avoir un point"
#: tiramisu/option.py:1018 #: tiramisu/option.py:1030
msgid "invalid domainname's length for {0} (min 2)" msgid "invalid domainname's length (max 255)"
msgstr "longueur du nom de domaine invalide pour {0} (minimum 2)" 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" msgid "invalid domainname"
msgstr "nom de domaine invalide" 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}" msgid "duplicate option name: {0}"
msgstr "nom de l'option dupliqué : {0}" msgstr "nom de l'option dupliqué : {0}"
#: tiramisu/option.py:1067 #: tiramisu/option.py:1144
msgid "unknown Option {0} in OptionDescription {1}" msgid "unknown Option {0} in OptionDescription {1}"
msgstr "Option {0} inconnue pour l'OptionDescription {1}" msgstr "Option {0} inconnue pour l'OptionDescription {1}"
#: tiramisu/option.py:1118 #: tiramisu/option.py:1195
msgid "duplicate option: {0}" msgid "duplicate option: {0}"
msgstr "option dupliquée : {0}" msgstr "option dupliquée : {0}"
#: tiramisu/option.py:1148 #: tiramisu/option.py:1225
msgid "consistency with option {0} which is not in Config" msgid "consistency with option {0} which is not in Config"
msgstr "consistency avec l'option {0} qui n'est pas dans une 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}" msgid "no option for path {0}"
msgstr "pas d'option pour le chemin {0}" msgstr "pas d'option pour le chemin {0}"
#: tiramisu/option.py:1162 #: tiramisu/option.py:1239
msgid "no option {0} found" msgid "no option {0} found"
msgstr "pas d'option {0} trouvée" 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})" 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})" 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" msgid "master group {0} shall not have a subgroup"
msgstr "groupe maître {0} ne doit pas avoir de sous-groupe" 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" msgid "master group {0} shall not have a symlinkoption"
msgstr "groupe maître {0} ne doit pas avoir de 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" msgid "not allowed option {0} in group {1}: this option is not a multi"
msgstr "" msgstr ""
"option non autorisée {0} dans le groupe {1} : cette option n'est pas une " "option non autorisée {0} dans le groupe {1} : cette option n'est pas une "
"multi" "multi"
#: tiramisu/option.py:1202 #: tiramisu/option.py:1277
msgid "master group with wrong master name for {0}" msgid "master group with wrong master name for {0}"
msgstr "le groupe maître avec un nom de maître érroné pour {0}" msgstr "le groupe maître avec un nom de maître érroné pour {0}"
#: tiramisu/option.py:1211 #: tiramisu/option.py:1285
msgid "no child has same nom has master group for: {0}" msgid "callback of master's option shall not refered a slave's ones"
msgstr "pas d'enfant avec le nom du groupe maître pour {0} " 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" msgid "group_type: {0} not allowed"
msgstr "group_type : {0} non autorisé" 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" msgid "malformed requirements type for option: {0}, must be a dict"
msgstr "" msgstr ""
"type requirements malformé pour l'option : {0}, doit être un dictionnaire" "type requirements malformé pour l'option : {0}, doit être un dictionnaire"
#: tiramisu/option.py:1323 #: tiramisu/option.py:1402
msgid "" msgid ""
"malformed requirements for option: {0} require must have option, expected " "malformed requirements for option: {0} require must have option, expected "
"and action keys" "and action keys"
@ -329,110 +359,110 @@ msgstr ""
"requirements malformé pour l'option : {0} l'exigence doit avoir les clefs " "requirements malformé pour l'option : {0} l'exigence doit avoir les clefs "
"option, expected et action" "option, expected et action"
#: tiramisu/option.py:1328 #: tiramisu/option.py:1407
msgid "malformed requirements for option: {0} inverse must be boolean" msgid "malformed requirements for option: {0} inverse must be boolean"
msgstr "" msgstr ""
"requirements mal formés pour l'option : {0} inverse doit être un booléen" "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" msgid "malformed requirements for option: {0} transitive must be boolean"
msgstr "" msgstr ""
"requirements mal formés pour l'option : {0} transitive doit être booléen" "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" msgid "malformed requirements for option: {0} same_action must be boolean"
msgstr "" msgstr ""
"requirements mal formés pour l'option : {0} same_action doit être un booléen" "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}" msgid "malformed requirements must be an option in option {0}"
msgstr "requirements mal formés doit être une option dans l'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" msgid "malformed requirements option {0} should not be a multi"
msgstr "requirements mal formés l'option {0} ne doit pas être une multi" msgstr "requirements mal formés l'option {0} ne doit pas être une multi"
#: tiramisu/option.py:1349 #: tiramisu/option.py:1428
msgid "" msgid ""
"malformed requirements second argument must be valid for option {0}: {1}" "malformed requirements second argument must be valid for option {0}: {1}"
msgstr "" msgstr ""
"requirements mal formés deuxième argument doit être valide pour l'option " "requirements mal formés deuxième argument doit être valide pour l'option "
"{0} : {1}" "{0} : {1}"
#: tiramisu/option.py:1354 #: tiramisu/option.py:1433
msgid "inconsistency in action types for option: {0} action: {1}" msgid "inconsistency in action types for option: {0} action: {1}"
msgstr "incohérence dans les types action pour l'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" msgid "{0} should be a function"
msgstr "{0} doit être une fonction" msgstr "{0} doit être une fonction"
#: tiramisu/option.py:1382 #: tiramisu/option.py:1461
msgid "{0}_params should be a dict" msgid "{0}_params should be a dict"
msgstr "{0}_params devrait être un 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" msgid "{0}_params with key {1} should not have length different to 1"
msgstr "" msgstr ""
"{0}_params avec la clef {1} devrait ne pas avoir une longueur différent de 1" "{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}\"" msgid "{0}_params should be tuple for key \"{1}\""
msgstr "{0}_params devrait être un tuple pour la clef \"{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" msgid "validator not support tuple"
msgstr "validator n'accepte pas de 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" 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" 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" 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" 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}" msgid "can't rebind {0}"
msgstr "ne peut redéfinir ({0})" msgstr "ne peut redéfinir ({0})"
#: tiramisu/setting.py:116 #: tiramisu/setting.py:121
msgid "can't unbind {0}" msgid "can't unbind {0}"
msgstr "ne peut supprimer ({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" msgid "cannot append {0} property for option {1}: this property is calculated"
msgstr "" msgstr ""
"ne peut ajouter la propriété {0} dans l'option {1}: cette propriété est " "ne peut ajouter la propriété {0} dans l'option {1}: cette propriété est "
"calculée" "calculée"
#: tiramisu/setting.py:317 #: tiramisu/setting.py:363
msgid "opt and all_properties must not be set together in reset" 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" 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" msgid "if opt is not None, path should not be None in _getproperties"
msgstr "" msgstr ""
"si opt n'est pas None, path devrait ne pas être à None dans _getproperties" "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" msgid "cannot change the value for option {0} this option is frozen"
msgstr "" msgstr ""
"ne peut modifier la valeur de l'option {0} cette option n'est pas modifiable" "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}" 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}" 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" msgid "permissive must be a tuple"
msgstr "permissive doit être un 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}" msgid "invalid generic owner {0}"
msgstr "invalide owner générique {0}" msgstr "invalide owner générique {0}"
#: tiramisu/setting.py:553 #: tiramisu/setting.py:602
msgid "" msgid ""
"malformed requirements imbrication detected for option: '{0}' with " "malformed requirements imbrication detected for option: '{0}' with "
"requirement on: '{1}'" "requirement on: '{1}'"
@ -440,75 +470,101 @@ msgstr ""
"imbrication de requirements mal formés detectée pour l'option : '{0}' avec " "imbrication de requirements mal formés detectée pour l'option : '{0}' avec "
"requirement sur : '{1}'" "requirement sur : '{1}'"
#: tiramisu/setting.py:565 #: tiramisu/setting.py:613
msgid "option '{0}' has requirement's property error: {1} {2}" 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}" 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" msgid "storage_type is already set, cannot rebind it"
msgstr "storage_type est déjà défini, impossible de le redéfinir" 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}" msgid "option {0} not already exists in storage {1}"
msgstr "option {0} n'existe pas dans l'espace de stockage {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" msgid "dictionary storage cannot delete session"
msgstr "" msgstr ""
"impossible de supprimer une session dans un espace de stockage dictionary" "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" msgid "session already used"
msgstr "session déjà utilisée" msgstr "session déjà utilisée"
#: tiramisu/storage/dictionary/storage.py:50 #: tiramisu/storage/dictionary/storage.py:52
msgid "a dictionary cannot be persistent" msgid "a dictionary cannot be persistent"
msgstr "un espace de stockage dictionary ne peut être persistant" 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}" msgid "no value for {0} cannot change owner to {1}"
msgstr "pas de valeur pour {0} ne peut changer d'utilisateur pour {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" 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" 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" msgid "invalid len for the master: {0} which has {1} as slave with greater len"
msgstr "" msgstr ""
"longueur invalide pour un maître : {0} qui a {1} une esclave avec une plus " "longueur invalide pour un maître : {0} qui a {1} une esclave avec une plus "
"grande longueur" "grande longueur"
#: tiramisu/value.py:468 #: tiramisu/value.py:496
msgid "cannot append a value on a multi option {0} which is a slave" 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" 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" 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" 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" msgid "cmp is not permitted in python v3 or greater"
msgstr "cmp n'est pas permis en python v3 ou supérieure" 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" 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" 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" 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" 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" 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" 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" 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" 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" #~ msgid ""
#~ msgstr "valeur invalide {0} pour l'option {1} qui doit être une liste" #~ "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" #~ msgid "invalid value {0} for option {1} must be different as {2} option"
#~ msgstr "" #~ msgstr ""

View File

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