refactor validation
authorEmmanuel Garette <egarette@cadoles.com>
Sat, 18 Apr 2015 20:53:45 +0000 (22:53 +0200)
committerEmmanuel Garette <egarette@cadoles.com>
Sat, 18 Apr 2015 20:53:45 +0000 (22:53 +0200)
14 files changed:
ChangeLog
test/test_option_consistency.py
tiramisu/autolib.py
tiramisu/config.py
tiramisu/option/baseoption.py
tiramisu/option/masterslave.py
tiramisu/option/option.py
tiramisu/option/optiondescription.py
tiramisu/storage/__init__.py
tiramisu/storage/dictionary/option.py
tiramisu/storage/sqlalchemy/option.py
tiramisu/value.py
translations/fr/tiramisu.po
translations/tiramisu.pot

index 3ebf62d..6daa435 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Sat Apr 18 22:42:53 2015 +0200 Emmanuel Garette <egarette@cadoles.com>
+       * refactor validation, build a fake context (with new Values and
+       Settings) to validate value with those object. Now value with
+       callback and consistency are correctly validate
+
 Sun Mar  8 12:02:17 2015 +0200 Emmanuel Garette <egarette@cadoles.com>
        * valid default/callback value in consistencies
 
index c419f7e..9be2507 100644 (file)
@@ -315,6 +315,15 @@ def return_netmask(*args, **kwargs):
     return u'255.255.255.0'
 
 
+def return_netmask2(master):
+    if master is not None:
+        if master.endswith('2.1'):
+            return u'255.255.255.0'
+        if not master.endswith('.0'):
+            return u'255.255.255.255'
+    return u'255.255.255.0'
+
+
 def test_consistency_network_netmask_multi_slave_callback():
     a = NetworkOption('a', '', multi=True, properties=('mandatory',))
     b = NetmaskOption('b', '', callback=return_netmask, multi=True, properties=('mandatory',))
@@ -339,6 +348,31 @@ def test_consistency_network_netmask_multi_slave_callback():
     c.a = [u'192.168.1.0', u'192.168.1.1']
 
 
+def test_consistency_network_netmask_multi_slave_callback_value():
+    a = NetworkOption('a', '', multi=True, properties=('mandatory',))
+    b = NetmaskOption('b', '', callback=return_netmask2, callback_params={'': ((a, False),)}, multi=True, properties=('mandatory',))
+    od = OptionDescription('a', '', [a, b])
+    od.impl_set_group_type(groups.master)
+    b.impl_add_consistency('network_netmask', a)
+    c = Config(od)
+    c.read_write()
+    c.cfgimpl_get_settings().remove('cache')
+    assert c.a == []
+    assert c.b == []
+    c.a.append(u'192.168.1.0')
+    assert c.a == [u'192.168.1.0']
+    assert c.b == [u'255.255.255.0']
+    raises(ValueError, "c.a[0] = u'192.168.2.1'")
+    assert c.a == [u'192.168.1.0']
+    assert c.b == [u'255.255.255.0']
+    raises(ValueError, "c.a = [u'192.168.2.1']")
+    assert c.a == [u'192.168.1.0']
+    assert c.b == [u'255.255.255.0']
+    c.a.append(u'192.168.1.1')
+    c.a = [u'192.168.1.0', u'192.168.1.1']
+    c.b = [u'255.255.255.0', u'255.255.255.255']
+
+
 def test_consistency_ip_netmask_multi_master():
     a = IPOption('a', '', multi=True)
     b = NetmaskOption('b', '', multi=True)
@@ -406,9 +440,7 @@ def test_consistency_broadcast_error():
     b.impl_add_consistency('network_netmask', a)
     c.impl_add_consistency('broadcast', a)
     c = Config(od)
-    c.a = ['192.168.1.0']
-    raises(ConfigError, "c.b = ['255.255.255.0']")
-    raises(ConfigError, "c.c = ['192.168.1.255']")
+    raises(ConfigError, "c.a = ['192.168.1.0']")
 
 
 def test_consistency_broadcast_default_1():
index 44bb82e..9096f8b 100644 (file)
@@ -24,12 +24,12 @@ from tiramisu.setting import undefined
 # ____________________________________________________________
 
 
-def carry_out_calculation(option, config, callback, callback_params,
+def carry_out_calculation(option, context, callback, callback_params,
                           index=undefined):
     """a function that carries out a calculation for an option's value
 
     :param option: the option
-    :param config: the context config in order to have
+    :param context: the context config in order to have
                    the whole options available
     :param callback: the name of the callback function
     :type callback: str
@@ -147,26 +147,26 @@ def carry_out_calculation(option, config, callback, callback_params,
     for key, callbacks in callback_params.items():
         for callbk in callbacks:
             if isinstance(callbk, tuple):
-                if config is undefined:
+                if context is undefined:
                     raise ContextError()  # pragma: optional cover
                 if callbk[0] is None:  # pragma: optional cover
                     #Not an option, set full context
-                    tcparams.setdefault(key, []).append((config, False))
+                    tcparams.setdefault(key, []).append((context, False))
                 else:
                     # callbk is something link (opt, True|False)
                     opt, force_permissive = callbk
                     if opt._is_subdyn():
-                        root = '.'.join(option.impl_getpath(config).split('.')[:-1])
+                        root = '.'.join(option.impl_getpath(context).split('.')[:-1])
                         name = opt.impl_getname() + option.impl_getsuffix()
                         path = root + '.' + name
                         opt = opt._impl_to_dyn(name, path)
                     else:
-                        path = config.cfgimpl_get_description(
+                        path = context.cfgimpl_get_description(
                         ).impl_get_path_by_opt(opt)
                     # get value
                     try:
-                        value = config.getattr(path, force_permissive=True,
-                                               validate=False)
+                        value = context.getattr(path, force_permissive=True,
+                                                validate=False)
                         # convert to list, not modifie this multi
                         if value.__class__.__name__ == 'Multi':
                             value = list(value)
index 56a1732..00fa53e 100644 (file)
 # ____________________________________________________________
 "options handler global entry point"
 import weakref
+from copy import copy
+
+
 from tiramisu.error import PropertiesOptionError, ConfigError, ConflictError
 from tiramisu.option import OptionDescription, Option, SymLinkOption, \
     DynSymLinkOption
 from tiramisu.option.baseoption import valid_name
 from tiramisu.setting import groups, Settings, default_encoding, undefined
 from tiramisu.storage import get_storages, get_storage, set_storage, \
-    _impl_getstate_setting
+    _impl_getstate_setting, get_storages_validation
 from tiramisu.value import Values, Multi
 from tiramisu.i18n import _
 
@@ -595,6 +598,14 @@ class _CommonConfig(SubConfig):
         self._impl_settings._impl_setstate(storage)
         self._impl_meta = None
 
+    def _gen_fake_values(self):
+        fake_config = Config(self._impl_descr, persistent=False,
+                             force_storages=get_storages_validation())
+        fake_config.cfgimpl_get_values()._p_._values = copy(self.cfgimpl_get_values()._p_.get_modified_values())
+        fake_config.cfgimpl_get_settings()._p_._properties = copy(self.cfgimpl_get_settings()._p_.get_modified_properties())
+        fake_config.cfgimpl_get_settings()._p_._permissives = copy(self.cfgimpl_get_settings()._p_.get_modified_permissives())
+        return fake_config
+
 
 # ____________________________________________________________
 class Config(_CommonConfig):
@@ -602,7 +613,7 @@ class Config(_CommonConfig):
     __slots__ = ('__weakref__', '_impl_test', '_impl_name')
 
     def __init__(self, descr, session_id=None, persistent=False,
-                 name=undefined):
+                 name=undefined, force_storages=None):
         """ Configuration option management master class
 
         :param descr: describes the configuration schema
@@ -615,7 +626,10 @@ class Config(_CommonConfig):
         :param persistent: if persistent, don't delete storage when leaving
         :type persistent: `boolean`
         """
+        #if force_storages is None:
         settings, values = get_storages(self, session_id, persistent)
+        #else:
+        #    settings, values = force_storages
         self._impl_settings = Settings(self, settings)
         self._impl_values = Values(self, values)
         super(Config, self).__init__(descr, weakref.ref(self))
index d9eb6c2..4197250 100644 (file)
@@ -135,6 +135,9 @@ class Base(StorageBase):
                                      list(set_forbidden_properties)))
         StorageBase.__init__(self, name, _multi, warnings_only, doc, extra,
                              calc_properties, requires, properties)
+        if multi is not False and default is None:
+            default = []
+        self.impl_validate(default)
         self._set_default_values(default, default_multi)
         if callback is not False:
             self.impl_set_callback(callback, callback_params)
@@ -507,7 +510,7 @@ class Option(OnlyOption):
         if current_opt is undefined:
             current_opt = self
 
-        def val_validator(val):
+        def calculation_validator(val):
             validator, validator_params = self.impl_get_validator()
             if validator is not None:
                 if validator_params != {}:
@@ -524,7 +527,7 @@ class Option(OnlyOption):
                 else:
                     validator_params_ = {'': (val,)}
                 # Raise ValueError if not valid
-                carry_out_calculation(self, config=context,
+                carry_out_calculation(self, context=context,
                                       callback=validator,
                                       callback_params=validator_params_)
 
@@ -545,7 +548,7 @@ class Option(OnlyOption):
             warning = None
             try:
                 # valid with self._validator
-                val_validator(_value)
+                calculation_validator(_value)
                 # if not context launch consistency validation
                 if context is not undefined:
                     descr._valid_consistency(current_opt, _value, context,
@@ -721,6 +724,7 @@ class Option(OnlyOption):
                                          None, all_cons_opts, warnings_only,
                                          transitive)
         self._add_consistency(func, all_cons_opts, params)
+        #re validate default value when add consistency
         self.impl_validate(self.impl_getdefault())
 
     def _cons_not_equal(self, opts, vals, warnings_only):
index f4dc738..462b6b3 100644 (file)
@@ -208,7 +208,8 @@ class MasterSlaves(object):
                                                          index=index,
                                                          setting_properties=setting_properties),
                              setitem=False,
-                             force=True)
+                             force=True,
+                             validate=validate)
         if validate_properties:
             context.cfgimpl_get_settings().validate_properties(opt, False,
                                                                False,
index ccbee14..d1927ea 100644 (file)
@@ -74,7 +74,7 @@ class ChoiceOption(Option):
             values_params = self._choice_values_params
             if values_params is None:
                 values_params = {}
-            values = carry_out_calculation(self, config=context,
+            values = carry_out_calculation(self, context=context,
                                            callback=values,
                                            callback_params=values_params)
             if not isinstance(values, list):  # pragma: optional cover
@@ -290,7 +290,7 @@ class PortOption(Option):
             except ValueError:  # pragma: optional cover
                 raise ValueError(_('invalid port'))
             if not self._get_extra('_min_value') <= val <= self._get_extra('_max_value'):  # pragma: optional cover
-                raise ValueError(_('invalid port, must be an between {0} '
+                raise ValueError(_('invalid port, must be an integer between {0} '
                                    'and {1}').format(self._get_extra('_min_value'),
                                                      self._get_extra('_max_value')))
 
index d719137..37171d2 100644 (file)
@@ -139,7 +139,7 @@ class OptionDescription(BaseOption, StorageOptionDescription):
                 option.impl_validate_options(cache_option)
         if init:
             if len(cache_option) != len(set(cache_option)):
-                for idx in xrange(1, len(cache_option)+1):
+                for idx in xrange(1, len(cache_option) + 1):
                     opt = cache_option.pop(0)
                     if opt in cache_option:
                         raise ConflictError(_('duplicate option: {0}').format(opt))
@@ -255,7 +255,7 @@ class OptionDescription(BaseOption, StorageOptionDescription):
 
     def _impl_get_suffixes(self, context):
         callback, callback_params = self.impl_get_callback()
-        values = carry_out_calculation(self, config=context,
+        values = carry_out_calculation(self, context=context,
                                        callback=callback,
                                        callback_params=callback_params)
         if len(values) > len(set(values)):
index 5e51f1d..e62bf19 100644 (file)
@@ -27,6 +27,7 @@ configurator ``set_storage()``.
 
 
 from time import time
+from random import randint
 import os
 from tiramisu.error import ConfigError
 from tiramisu.i18n import _
@@ -66,6 +67,8 @@ class StorageType(object):
 
 storage_type = StorageType()
 storage_option_type = StorageType()
+storage_validation = StorageType()
+storage_validation.set('dictionary')
 
 
 def set_storage(type_, name, **kwargs):  # pragma: optional cover
@@ -105,13 +108,15 @@ def get_storage(type_, session_id, persistent, test):  # pragma: optional cover
     """
     if type_ == 'option':
         return storage_option_type.get().Storage(session_id, persistent, test)
-    else:
+    elif type_ == 'config':
         return storage_type.get().Storage(session_id, persistent, test)
+    else:
+        return storage_validation.get().Storage(session_id, persistent, test)
 
 
 def get_storages(context, session_id, persistent):
     def gen_id(config):
-        return str(id(config)) + str(time())
+        return str(id(config)) + str(time()) + str(randint(0, 500))
 
     if session_id is None:
         session_id = gen_id(context)
@@ -119,10 +124,8 @@ def get_storages(context, session_id, persistent):
     storage = imp.Storage(session_id, persistent)
     try:
         return imp.Settings(storage), imp.Values(storage)
-    except:
-        import traceback
-        traceback.print_exc()
-        raise Exception('rah')
+    except Exception, err:
+        raise Exception(_('unable to get storages:') + str(err))
 
 
 def get_storages_option(type_):
@@ -133,6 +136,12 @@ def get_storages_option(type_):
         return imp.StorageOptionDescription
 
 
+def get_storages_validation():
+    imp = storage_validation.get()
+    storage = imp.Storage('pouet', persistent=False, test=True)
+    return imp.Settings(storage), imp.Values(storage)
+
+
 def list_sessions(type_):  # pragma: optional cover
     """List all available session (persistent or not persistent)
     """
index 0132152..f6b19b3 100644 (file)
@@ -83,9 +83,6 @@ class StorageBase(object):
             self._opt = opt
 
     def _set_default_values(self, default, default_multi):
-        if self.impl_is_multi() and default is None:
-                default = []
-        self.impl_validate(default)
         if ((self.impl_is_multi() and default != tuple()) or
                 (not self.impl_is_multi() and default is not None)):
             if self.impl_is_multi():
index b4ea9dc..4c2e983 100644 (file)
@@ -322,9 +322,6 @@ class _Base(SqlAlchemyBase):
         _Consistency(func, all_cons_opts, params)
 
     def _set_default_values(self, default, default_multi):
-        if self.impl_is_multi() and default is None:
-                default = []
-        self.impl_validate(default)
         self._default = default
         if self.impl_is_multi() and default_multi is not None:
             self._validate(default_multi)
index ea60508..eed993b 100644 (file)
@@ -83,7 +83,7 @@ class Values(object):
         # if value has callback and is not set
         if opt.impl_has_callback():
             callback, callback_params = opt.impl_get_callback()
-            value = carry_out_calculation(opt, config=self._getcontext(),
+            value = carry_out_calculation(opt, context=self._getcontext(),
                                           callback=callback,
                                           callback_params=callback_params,
                                           index=index)
@@ -161,8 +161,12 @@ class Values(object):
         if self._contains(path):
             if validate:
                 setting = context.cfgimpl_get_settings()
-                opt.impl_validate(opt.impl_getdefault(),
-                                  context, 'validator' in setting)
+                fake_context = context._gen_fake_values()
+                setting_properties = setting._getproperties()
+                fake_value = fake_context.cfgimpl_get_values()
+                fake_value.reset(opt, path, validate=False)
+                opt.impl_validate(getattr(fake_context, path),
+                                  fake_context, 'validator' in setting_properties)
             context.cfgimpl_reset_cache()
             if opt.impl_is_master_slaves('master'):
                 opt.impl_get_master_slaves().reset(opt, self)
@@ -331,8 +335,16 @@ class Values(object):
         # valid opt
         context = self._getcontext()
         setting_properties = context.cfgimpl_get_settings()._getproperties()
-        opt.impl_validate(value, context,
-                          'validator' in setting_properties)
+        fake_context = context._gen_fake_values()
+        fake_context.cfgimpl_get_values()._setitem(opt, value, path,
+                                                   force_permissive, is_write,
+                                                   setting_properties)
+        opt.impl_validate(value, fake_context, 'validator' in setting_properties)
+        self._setitem(opt, value, path, force_permissive, is_write,
+                      setting_properties)
+
+    def _setitem(self, opt, value, path, force_permissive, is_write,
+                 setting_properties):
         if opt.impl_is_master_slaves():
             opt.impl_get_master_slaves().setitem(self, opt, value, path)
         self._setvalue(opt, path, value, force_permissive=force_permissive,
@@ -607,8 +619,13 @@ class Multi(list):
     def __setitem__(self, index, value):
         self._setitem(index, value)
 
-    def _setitem(self, index, value):
-        self._validate(value, index, True)
+    def _setitem(self, index, value, validate=True):
+        if validate:
+            fake_context = self._getcontext()._gen_fake_values()
+            fake_multi = fake_context.cfgimpl_get_values()._get_cached_item(
+                self.opt, path=self.path, validate=False)
+            fake_multi._setitem(index, value, validate=False)
+            self._validate(value, fake_context, index, True)
         #assume not checking mandatory property
         super(Multi, self).__setitem__(index, value)
         self._getcontext().cfgimpl_get_values()._setvalue(self.opt, self.path,
@@ -626,7 +643,7 @@ class Multi(list):
                                            True, False, None, True,
                                            index=index)
 
-    def append(self, value=undefined, force=False, setitem=True):
+    def append(self, value=undefined, force=False, setitem=True, validate=True):
         """the list value can be updated (appened)
         only if the option is a master
         """
@@ -639,7 +656,12 @@ class Multi(list):
                 value = self._get_validated_value(index)
             except IndexError:
                 value = None
-        self._validate(value, index, True)
+        if validate and value not in [None, undefined]:
+            fake_context = self._getcontext()._gen_fake_values()
+            fake_multi = fake_context.cfgimpl_get_values()._get_cached_item(
+                self.opt, path=self.path, validate=False)
+            fake_multi.append(value, validate=False, force=True)
+            self._validate(value, fake_context, index, True)
         if not '_index' in self.__slots__ and self.opt.impl_is_submulti():
             if not isinstance(value, SubMulti):
                 value = SubMulti(value, self.context, self.opt, self.path, index)
@@ -668,16 +690,21 @@ class Multi(list):
         super(Multi, self).reverse()
         self._store()
 
-    def insert(self, index, obj):
-        #FIXME obj should be undefined
+    def insert(self, index, value, validate=True):
+        #FIXME value should be undefined
         if self.opt.impl_is_master_slaves():
             raise SlaveError(_("cannot insert multi option {0} if master or "
                                "slave").format(self.opt.impl_getname()))
-        self._validate(obj, index, True)
-        super(Multi, self).insert(index, obj)
+        if value is not None and validate:
+            fake_context = self._getcontext()._gen_fake_values()
+            fake_multi = fake_context.cfgimpl_get_values()._get_cached_item(
+                self.opt, path=self.path, validate=False)
+            fake_multi.insert(index, value, validate=False)
+            self._validate(value, fake_context, index, True)
+        super(Multi, self).insert(index, value)
         self._store()
 
-    def extend(self, iterable):
+    def extend(self, iterable, validate=True):
         if self.opt.impl_is_master_slaves():
             raise SlaveError(_("cannot extend multi option {0} if master or "
                                "slave").format(self.opt.impl_getname()))
@@ -685,14 +712,18 @@ class Multi(list):
             index = self._index
         except:
             index = None
-        self._validate(iterable, index)
+        if validate:
+            fake_context = self._getcontext()._gen_fake_values()
+            fake_multi = fake_context.cfgimpl_get_values()._get_cached_item(
+                self.opt, path=self.path, validate=False)
+            fake_multi.extend(iterable, validate=False)
+            self._validate(iterable, fake_context, index)
         super(Multi, self).extend(iterable)
         self._store()
 
-    def _validate(self, value, force_index, submulti=False):
-        if value is not None:
-            self.opt.impl_validate(value, context=self._getcontext(),
-                                   force_index=force_index)
+    def _validate(self, value, fake_context, force_index, submulti=False):
+        self.opt.impl_validate(value, context=fake_context,
+                               force_index=force_index)
 
     def pop(self, index, force=False):
         """the list value can be updated (poped)
@@ -749,12 +780,13 @@ class SubMulti(Multi):
                                                           self.path,
                                                           self.submulti())
 
-    def _validate(self, value, force_index, submulti=False):
+    def _validate(self, value, fake_context, force_index, submulti=False):
         if value is not None:
             if submulti is False:
-                super(SubMulti, self)._validate(value, force_index)
+                super(SubMulti, self)._validate(value, fake_context,
+                                                force_index, submulti)
             else:
-                self.opt.impl_validate(value, context=self._getcontext(),
+                self.opt.impl_validate(value, context=fake_context,
                                        force_index=self._index,
                                        force_submulti_index=force_index)
 
index c330ceb..f782bb7 100644 (file)
@@ -2,7 +2,7 @@ msgid ""
 msgstr ""
 "Project-Id-Version: Tiramisu\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2014-12-07 14:44+CET\n"
+"POT-Creation-Date: 2015-04-18 22:40+CEST\n"
 "PO-Revision-Date: \n"
 "Last-Translator: Emmanuel Garette <egarette@cadoles.com>\n"
 "Language-Team: Tiramisu's team <egarette@cadoles.com>\n"
@@ -10,7 +10,7 @@ msgstr ""
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"X-Generator: Poedit 1.5.4\n"
+"X-Generator: Poedit 1.7.5\n"
 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
 "X-Poedit-SourceCharset: UTF-8\n"
 
@@ -21,92 +21,92 @@ msgstr ""
 "impossible d'effectuer le calcul, l'option {0} a les propriétés : {1} pour : "
 "{2}"
 
-#: tiramisu/config.py:59
+#: tiramisu/config.py:62
 msgid "descr must be an optiondescription, not {0}"
 msgstr "descr doit être une optiondescription pas un {0}"
 
-#: tiramisu/config.py:139
+#: tiramisu/config.py:142
 msgid "unknown group_type: {0}"
 msgstr "group_type inconnu: {0}"
 
-#: tiramisu/config.py:178 tiramisu/setting.py:320 tiramisu/value.py:54
-#: tiramisu/value.py:605
+#: tiramisu/config.py:181 tiramisu/setting.py:320 tiramisu/value.py:54
+#: tiramisu/value.py:616
 msgid "the context does not exist anymore"
 msgstr "le context n'existe plus"
 
-#: tiramisu/config.py:183
+#: tiramisu/config.py:186
 msgid "no option description found for this config (may be GroupConfig)"
 msgstr ""
 "pas d'option description trouvé pour cette config (peut être un GroupConfig)"
 
-#: tiramisu/config.py:211
+#: tiramisu/config.py:214
 msgid "can't assign to an OptionDescription"
 msgstr "ne peut pas attribuer une valeur à une OptionDescription"
 
-#: tiramisu/config.py:340
+#: tiramisu/config.py:343
 msgid "unknown type_ type {0}for _find"
 msgstr "type_ type {0} pour _find inconnu"
 
-#: tiramisu/config.py:380
+#: tiramisu/config.py:383
 msgid "no option found in config with these criteria"
 msgstr "aucune option trouvée dans la config avec ces critères"
 
-#: tiramisu/config.py:430
+#: tiramisu/config.py:433
 msgid "make_dict can't filtering with value without option"
 msgstr "make_dict ne peut filtrer sur une valeur mais sans option"
 
-#: tiramisu/config.py:449
+#: tiramisu/config.py:452
 msgid "unexpected path {0}, should start with {1}"
 msgstr "chemin imprévu {0}, devrait commencer par {1}"
 
-#: tiramisu/config.py:519
+#: tiramisu/config.py:522
 msgid "opt in getowner must be an option not {0}"
 msgstr "opt dans getowner doit être une option pas {0}"
 
-#: tiramisu/config.py:564
+#: tiramisu/config.py:567
 msgid "cannot serialize Config with MetaConfig"
 msgstr "impossible de sérialiser une Config avec une MetaConfig"
 
-#: tiramisu/config.py:578
+#: tiramisu/config.py:581
 msgid "this storage is not serialisable, could be a none persistent storage"
 msgstr "ce storage n'est sérialisable, devrait être une storage non persistant"
 
-#: tiramisu/config.py:631
+#: tiramisu/config.py:645
 msgid "invalid name: {0} for config"
 msgstr "nom invalide : {0} pour la config"
 
-#: tiramisu/config.py:655
+#: tiramisu/config.py:669
 msgid "groupconfig's children must be a list"
 msgstr "enfants d'une groupconfig doit être une liste"
 
-#: tiramisu/config.py:659
+#: tiramisu/config.py:673
 msgid "groupconfig's children must be Config, MetaConfig or GroupConfig"
 msgstr ""
 "les enfants d'un groupconfig doivent être des Config, MetaConfig ou "
 "GroupConfig"
 
-#: tiramisu/config.py:662
+#: tiramisu/config.py:676
 msgid "name must be set to config before creating groupconfig"
 msgstr "un nom doit être donné à la config avant de créer un groupconfig"
 
-#: tiramisu/config.py:670
+#: tiramisu/config.py:684
 msgid "config name must be uniq in groupconfig for {0}"
 msgstr "le nom de la config doit être unique dans un groupconfig pour {0}"
 
-#: tiramisu/config.py:785
+#: tiramisu/config.py:799
 msgid "metaconfig's children should be config, not {0}"
 msgstr "enfants d'une metaconfig doit être une config, pas {0}"
 
-#: tiramisu/config.py:789
+#: tiramisu/config.py:803
 msgid "child has already a metaconfig's"
 msgstr "enfant a déjà une metaconfig"
 
-#: tiramisu/config.py:793
+#: tiramisu/config.py:807
 msgid "all config in metaconfig must have the same optiondescription"
 msgstr ""
 "toutes les configs d'une metaconfig doivent avoir la même optiondescription"
 
-#: tiramisu/config.py:805
+#: tiramisu/config.py:819
 msgid ""
 "force_default, force_default_if_same or force_dont_change_value cannot be "
 "set with only_config"
@@ -114,7 +114,7 @@ msgstr ""
 "force_default, force_default_if_same ou force_dont_change_value ne peuvent "
 "pas être spécifié avec only_config"
 
-#: tiramisu/config.py:811
+#: tiramisu/config.py:825
 msgid "force_default and force_dont_change_value cannot be set together"
 msgstr ""
 "force_default et force_dont_change_value ne peuvent pas être mis ensemble"
@@ -172,7 +172,7 @@ msgstr ""
 msgid "invalid properties type {0} for {1}, must be a tuple"
 msgstr "type des properties invalide {0} pour {1}, doit être un tuple"
 
-#: tiramisu/option/baseoption.py:145
+#: tiramisu/option/baseoption.py:148
 msgid ""
 "params defined for a callback function but no callback defined yet for "
 "option {0}"
@@ -180,115 +180,115 @@ msgstr ""
 "params définis pour une fonction callback mais par de callback encore "
 "définis pour l'option {0}"
 
-#: tiramisu/option/baseoption.py:150
+#: tiramisu/option/baseoption.py:153
 msgid "a callback is already set for option {0}, cannot set another one's"
 msgstr ""
 "un callback est en lecture seul pour l'option {0}, ne peut en placer une "
 "autre"
 
-#: tiramisu/option/baseoption.py:277
+#: tiramisu/option/baseoption.py:280
 msgid "cannot serialize Option, only in OptionDescription"
 msgstr "ne peut serialiser une Option, seulement via une OptionDescription"
 
-#: tiramisu/option/baseoption.py:363
+#: tiramisu/option/baseoption.py:366
 msgid "'{0}' ({1}) object attribute '{2}' is read-only"
 msgstr "l'attribut {2} de l'objet '{0}' ({1}) est en lecture seule"
 
-#: tiramisu/option/baseoption.py:528 tiramisu/option/baseoption.py:571
+#: tiramisu/option/baseoption.py:545 tiramisu/option/baseoption.py:588
 msgid "invalid value for option {0}: {1}"
 msgstr "valeur invalide pour l'option {0} : {1}"
 
-#: tiramisu/option/baseoption.py:541
+#: tiramisu/option/baseoption.py:558
 msgid "do_validation for {0}: error in value"
 msgstr "do_validation for {0} : erreur dans un la valeur"
 
-#: tiramisu/option/baseoption.py:547
+#: tiramisu/option/baseoption.py:564
 msgid "do_validation for {0}: warning in value"
 msgstr "do_validation for {0} : warning dans un la valeur"
 
-#: tiramisu/option/baseoption.py:557
+#: tiramisu/option/baseoption.py:574
 msgid "do_validation for {0}: error in consistency"
 msgstr "do_validation for {0} : erreur dans un test de consistance"
 
-#: tiramisu/option/baseoption.py:561
+#: tiramisu/option/baseoption.py:578
 msgid "do_validation for {0}: warning in consistency"
 msgstr "do_validation for {0} : warning dans un test de consistance"
 
-#: tiramisu/option/baseoption.py:565
+#: tiramisu/option/baseoption.py:582
 msgid "warning on the value of the option {0}: {1}"
 msgstr "avertissement sur la valeur de l'option {0} : {1}"
 
-#: tiramisu/option/baseoption.py:583 tiramisu/option/baseoption.py:592
+#: tiramisu/option/baseoption.py:600 tiramisu/option/baseoption.py:609
 msgid "invalid value {0} for option {1} which must be a list"
 msgstr "valeur invalide pour l'option {0} : {1} laquelle doit être une liste"
 
-#: tiramisu/option/baseoption.py:598
+#: tiramisu/option/baseoption.py:615
 msgid "invalid value {0} for option {1} which must be a list of list"
 msgstr ""
 "valeur invalide pour l'option {0} : {1} laquelle doit être une liste de liste"
 
-#: tiramisu/option/baseoption.py:651
+#: tiramisu/option/baseoption.py:668
 msgid "'{0}' ({1}) cannot add consistency, option is read-only"
 msgstr ""
 "'{0}' ({1}) ne peut ajouter de consistency, l'option est en lecture seul"
 
-#: tiramisu/option/baseoption.py:663
+#: tiramisu/option/baseoption.py:680
 msgid "unknow parameter {0} in consistency"
 msgstr "paramètre inconnu {0} dans un test de consistance"
 
-#: tiramisu/option/baseoption.py:670
+#: tiramisu/option/baseoption.py:687
 msgid "consistency must be set with an option"
 msgstr "consistency doit être configuré avec une option"
 
-#: tiramisu/option/baseoption.py:673 tiramisu/option/baseoption.py:680
+#: tiramisu/option/baseoption.py:690 tiramisu/option/baseoption.py:697
 msgid ""
 "almost one option in consistency is in a dynoptiondescription but not all"
 msgstr ""
 "au moins une option dans le test de consistance est dans une "
 "dynoptiondescription mais pas toutes"
 
-#: tiramisu/option/baseoption.py:676
+#: tiramisu/option/baseoption.py:693
 msgid "option in consistency must be in same dynoptiondescription"
 msgstr ""
 "option dans une consistency doit être dans le même dynoptiondescription"
 
-#: tiramisu/option/baseoption.py:683
+#: tiramisu/option/baseoption.py:700
 msgid "cannot add consistency with itself"
 msgstr "ne peut ajouter une consistency avec lui même"
 
-#: tiramisu/option/baseoption.py:685
+#: tiramisu/option/baseoption.py:702
 msgid "every options in consistency must be multi or none"
 msgstr ""
 "toutes les options d'une consistency doivent être multi ou ne pas l'être"
 
-#: tiramisu/option/baseoption.py:689
+#: tiramisu/option/baseoption.py:706
 msgid "consistency {0} not available for this option"
 msgstr "consistency {0} non valable pour cette option"
 
-#: tiramisu/option/baseoption.py:717
+#: tiramisu/option/baseoption.py:735
 msgid "same value for {0} and {1}, should be different"
 msgstr "même valeur pour {0} et {1}, devrait être différent"
 
-#: tiramisu/option/baseoption.py:719
+#: tiramisu/option/baseoption.py:737
 msgid "same value for {0} and {1}, must be different"
 msgstr "même valeur pour {0} et {1}, doit être différent"
 
-#: tiramisu/option/baseoption.py:776
+#: tiramisu/option/baseoption.py:794
 msgid "default value not allowed if option: {0} is calculated"
 msgstr "la valeur par défaut n'est pas possible si l'option {0} est calculée"
 
-#: tiramisu/option/baseoption.py:798
+#: tiramisu/option/baseoption.py:816
 msgid "malformed requirements type for option: {0}, must be a dict"
 msgstr ""
 "type requirements malformé pour l'option : {0}, doit être un dictionnaire"
 
-#: tiramisu/option/baseoption.py:804
+#: tiramisu/option/baseoption.py:822
 msgid "malformed requirements for option: {0} unknown keys {1}, must only {2}"
 msgstr ""
 "requirements mal formés pour l'option : {0} clefs inconnues {1}, doit "
 "seulement avoir {2}"
 
-#: tiramisu/option/baseoption.py:815
+#: tiramisu/option/baseoption.py:833
 msgid ""
 "malformed requirements for option: {0} require must have option, expected "
 "and action keys"
@@ -296,49 +296,49 @@ msgstr ""
 "requirements malformé pour l'option : {0} l'exigence doit avoir les clefs "
 "option, expected et action"
 
-#: tiramisu/option/baseoption.py:819
+#: tiramisu/option/baseoption.py:837
 msgid ""
 "malformed requirements for option: {0} action cannot be force_store_value"
 msgstr ""
 "requirements mal formés pour l'option : {0} action ne peut pas être "
 "force_store_value"
 
-#: tiramisu/option/baseoption.py:824
+#: tiramisu/option/baseoption.py:842
 msgid "malformed requirements for option: {0} inverse must be boolean"
 msgstr ""
 "requirements mal formés pour l'option : {0} inverse doit être un booléen"
 
-#: tiramisu/option/baseoption.py:828
+#: tiramisu/option/baseoption.py:846
 msgid "malformed requirements for option: {0} transitive must be boolean"
 msgstr ""
 "requirements mal formés pour l'option : {0} transitive doit être booléen"
 
-#: tiramisu/option/baseoption.py:832
+#: tiramisu/option/baseoption.py:850
 msgid "malformed requirements for option: {0} same_action must be boolean"
 msgstr ""
 "requirements mal formés pour l'option : {0} same_action doit être un booléen"
 
-#: tiramisu/option/baseoption.py:836
+#: tiramisu/option/baseoption.py:854
 msgid "malformed requirements must be an option in option {0}"
 msgstr "requirements mal formés doit être une option dans l'option {0}"
 
-#: tiramisu/option/baseoption.py:839
+#: tiramisu/option/baseoption.py:857
 msgid "malformed requirements option {0} must not be a multi for {1}"
 msgstr ""
 "requirements mal formés pour l'option {0} ne doit pas être une multi pour {1}"
 
-#: tiramisu/option/baseoption.py:846
+#: tiramisu/option/baseoption.py:864
 msgid ""
 "malformed requirements second argument must be valid for option {0}: {1}"
 msgstr ""
 "requirements mal formés deuxième argument doit être valide pour l'option "
 "{0} : {1}"
 
-#: tiramisu/option/baseoption.py:851
+#: tiramisu/option/baseoption.py:869
 msgid "inconsistency in action types for option: {0} action: {1}"
 msgstr "incohérence dans les types action pour l'option : {0} action {1}"
 
-#: tiramisu/option/baseoption.py:879
+#: tiramisu/option/baseoption.py:897
 msgid "malformed symlinkoption must be an option for symlink {0}"
 msgstr "symlinkoption mal formé, doit être une option pour symlink {0}"
 
@@ -366,7 +366,7 @@ msgstr ""
 "callback d'une variable maitre ne devrait pas référencer des variables "
 "esclaves"
 
-#: tiramisu/option/masterslave.py:258
+#: tiramisu/option/masterslave.py:259
 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"
 
@@ -462,8 +462,8 @@ msgid "invalid port"
 msgstr "port invalide"
 
 #: tiramisu/option/option.py:293
-msgid "invalid port, must be an between {0} and {1}"
-msgstr "port invalide, port doit être entre {0} et {1}"
+msgid "invalid port, must be an integer between {0} and {1}"
+msgstr "port invalide, port doit être nombre entre {0} et {1}"
 
 #: tiramisu/option/option.py:306
 msgid "invalid network address"
@@ -664,7 +664,7 @@ msgstr "tentative d'accès à une option nommée : {0} avec les propriétés {1}
 msgid "permissive must be a tuple"
 msgstr "permissive doit être un tuple"
 
-#: tiramisu/setting.py:508 tiramisu/value.py:426
+#: tiramisu/setting.py:508 tiramisu/value.py:437
 msgid "invalid generic owner {0}"
 msgstr "invalide owner générique {0}"
 
@@ -680,52 +680,56 @@ msgstr ""
 msgid "option '{0}' has requirement's property error: {1} {2}"
 msgstr "l'option '{0}' a une erreur de propriété pour le requirement : {1} {2}"
 
-#: tiramisu/storage/__init__.py:48
+#: tiramisu/storage/__init__.py:49
 msgid "storage_type is already set, cannot rebind it"
 msgstr "storage_type est déjà défini, impossible de le redéfinir"
 
-#: tiramisu/storage/__init__.py:59
+#: tiramisu/storage/__init__.py:60
 msgid "cannot import the storage {0}"
 msgstr "ne peut pas importer le stockage {0}"
 
-#: tiramisu/storage/__init__.py:90
+#: tiramisu/storage/__init__.py:93
 msgid "option {0} not already exists in storage {1}"
 msgstr "option {0} n'existe pas dans l'espace de stockage {1}"
 
-#: tiramisu/storage/dictionary/option.py:99
+#: tiramisu/storage/__init__.py:128
+msgid "unable to get storages:"
+msgstr "impossible de récupérer les storages :"
+
+#: tiramisu/storage/dictionary/option.py:96
 msgid "invalid default_multi value {0} for option {1}: {2}"
 msgstr "la valeur default_multi est invalide {0} pour l'option {1} : {2}"
 
-#: tiramisu/storage/dictionary/option.py:141
-#: tiramisu/storage/sqlalchemy/option.py:434 tiramisu/value.py:490
+#: tiramisu/storage/dictionary/option.py:138
+#: tiramisu/storage/sqlalchemy/option.py:431 tiramisu/value.py:501
 msgid "information's item not found: {0}"
 msgstr "aucune config spécifiée alors que c'est nécessaire"
 
-#: tiramisu/storage/dictionary/option.py:362
-#: tiramisu/storage/sqlalchemy/option.py:478
+#: tiramisu/storage/dictionary/option.py:359
+#: tiramisu/storage/sqlalchemy/option.py:475
 msgid "no option for path {0}"
 msgstr "pas d'option pour le chemin {0}"
 
-#: tiramisu/storage/dictionary/option.py:368
-#: tiramisu/storage/sqlalchemy/option.py:485
+#: tiramisu/storage/dictionary/option.py:365
+#: tiramisu/storage/sqlalchemy/option.py:482
 msgid "no option {0} found"
 msgstr "pas d'option {0} trouvée"
 
-#: tiramisu/storage/dictionary/option.py:417
+#: tiramisu/storage/dictionary/option.py:414
 msgid "cannot find dynpath"
 msgstr "ne peut trouver le dynpath"
 
-#: tiramisu/storage/dictionary/option.py:507
-#: tiramisu/storage/sqlalchemy/option.py:630
+#: tiramisu/storage/dictionary/option.py:504
+#: tiramisu/storage/sqlalchemy/option.py:627
 msgid "suffix and context needed if it's a dyn option"
 msgstr "suffix et context obligatoire si c'est une option dynamique"
 
-#: tiramisu/storage/dictionary/option.py:520
+#: tiramisu/storage/dictionary/option.py:517
 msgid "{0} instance has no attribute '_readonly'"
 msgstr "{0} instance n'a pas l'attribut '_readonly'"
 
-#: tiramisu/storage/dictionary/option.py:534
-#: tiramisu/storage/sqlalchemy/option.py:660
+#: tiramisu/storage/dictionary/option.py:531
+#: tiramisu/storage/sqlalchemy/option.py:657
 msgid "unknown Option {0} in OptionDescription {1}"
 msgstr "Option {0} inconnue pour l'OptionDescription {1}"
 
@@ -747,52 +751,52 @@ msgstr "un espace de stockage dictionary ne peut être persistant"
 msgid "optiondescription has no value"
 msgstr "une optiondescription n'a pas de valeur"
 
-#: tiramisu/value.py:325
+#: tiramisu/value.py:329
 msgid "you should only set value with config"
 msgstr "vous devez seul affecter une valeur avec un config"
 
-#: tiramisu/value.py:395
+#: tiramisu/value.py:406
 msgid "owner only avalaible for an option"
 msgstr "owner seulement possible pour une option"
 
-#: tiramisu/value.py:433
+#: tiramisu/value.py:444
 msgid "no value for {0} cannot change owner to {1}"
 msgstr "pas de valeur pour {0} ne peut changer d'utilisateur pour {1}"
 
-#: tiramisu/value.py:531
+#: tiramisu/value.py:542
 msgid "can force cache only if cache is actived in config"
 msgstr ""
 "peut force la mise en cache seulement si le cache est activé dans la config"
 
-#: tiramisu/value.py:570
+#: tiramisu/value.py:581
 msgid "{0} is already a Multi "
 msgstr "{0} est déjà une Multi"
 
-#: tiramisu/value.py:636
+#: tiramisu/value.py:651
 msgid "cannot append a value on a multi option {0} which is a slave"
 msgstr "ne peut ajouter une valeur sur l'option multi {0} qui est une esclave"
 
-#: tiramisu/value.py:655
+#: tiramisu/value.py:675
 msgid "cannot sort multi option {0} if master or slave"
 msgstr "ne peut trier une option multi {0} pour une maître ou une esclave"
 
-#: tiramisu/value.py:659
+#: tiramisu/value.py:679
 msgid "cmp is not permitted in python v3 or greater"
 msgstr "cmp n'est pas permis en python v3 ou supérieure"
 
-#: tiramisu/value.py:668
+#: tiramisu/value.py:688
 msgid "cannot reverse multi option {0} if master or slave"
 msgstr "ne peut inverser une option multi {0} pour une maître ou une esclave"
 
-#: tiramisu/value.py:676
+#: tiramisu/value.py:696
 msgid "cannot insert multi option {0} if master or slave"
 msgstr "ne peut insérer une option multi {0} pour une maître ou une esclave"
 
-#: tiramisu/value.py:684
+#: tiramisu/value.py:709
 msgid "cannot extend multi option {0} if master or slave"
 msgstr "ne peut étendre une option multi {0} pour une maître ou une esclave"
 
-#: tiramisu/value.py:712
+#: tiramisu/value.py:741
 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"
 
index 5cc896f..e124107 100644 (file)
@@ -5,7 +5,7 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: PACKAGE VERSION\n"
-"POT-Creation-Date: 2014-12-07 14:44+CET\n"
+"POT-Creation-Date: 2015-04-18 22:40+CEST\n"
 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -19,92 +19,92 @@ msgstr ""
 msgid "unable to carry out a calculation, option {0} has properties: {1} for: {2}"
 msgstr ""
 
-#: tiramisu/config.py:59
+#: tiramisu/config.py:62
 msgid "descr must be an optiondescription, not {0}"
 msgstr ""
 
-#: tiramisu/config.py:139
+#: tiramisu/config.py:142
 msgid "unknown group_type: {0}"
 msgstr ""
 
-#: tiramisu/config.py:178 tiramisu/setting.py:320 tiramisu/value.py:54
-#: tiramisu/value.py:605
+#: tiramisu/config.py:181 tiramisu/setting.py:320 tiramisu/value.py:54
+#: tiramisu/value.py:616
 msgid "the context does not exist anymore"
 msgstr ""
 
-#: tiramisu/config.py:183
+#: tiramisu/config.py:186
 msgid "no option description found for this config (may be GroupConfig)"
 msgstr ""
 
-#: tiramisu/config.py:211
+#: tiramisu/config.py:214
 msgid "can't assign to an OptionDescription"
 msgstr ""
 
-#: tiramisu/config.py:340
+#: tiramisu/config.py:343
 msgid "unknown type_ type {0}for _find"
 msgstr ""
 
-#: tiramisu/config.py:380
+#: tiramisu/config.py:383
 msgid "no option found in config with these criteria"
 msgstr ""
 
-#: tiramisu/config.py:430
+#: tiramisu/config.py:433
 msgid "make_dict can't filtering with value without option"
 msgstr ""
 
-#: tiramisu/config.py:449
+#: tiramisu/config.py:452
 msgid "unexpected path {0}, should start with {1}"
 msgstr ""
 
-#: tiramisu/config.py:519
+#: tiramisu/config.py:522
 msgid "opt in getowner must be an option not {0}"
 msgstr ""
 
-#: tiramisu/config.py:564
+#: tiramisu/config.py:567
 msgid "cannot serialize Config with MetaConfig"
 msgstr ""
 
-#: tiramisu/config.py:578
+#: tiramisu/config.py:581
 msgid "this storage is not serialisable, could be a none persistent storage"
 msgstr ""
 
-#: tiramisu/config.py:631
+#: tiramisu/config.py:645
 msgid "invalid name: {0} for config"
 msgstr ""
 
-#: tiramisu/config.py:655
+#: tiramisu/config.py:669
 msgid "groupconfig's children must be a list"
 msgstr ""
 
-#: tiramisu/config.py:659
+#: tiramisu/config.py:673
 msgid "groupconfig's children must be Config, MetaConfig or GroupConfig"
 msgstr ""
 
-#: tiramisu/config.py:662
+#: tiramisu/config.py:676
 msgid "name must be set to config before creating groupconfig"
 msgstr ""
 
-#: tiramisu/config.py:670
+#: tiramisu/config.py:684
 msgid "config name must be uniq in groupconfig for {0}"
 msgstr ""
 
-#: tiramisu/config.py:785
+#: tiramisu/config.py:799
 msgid "metaconfig's children should be config, not {0}"
 msgstr ""
 
-#: tiramisu/config.py:789
+#: tiramisu/config.py:803
 msgid "child has already a metaconfig's"
 msgstr ""
 
-#: tiramisu/config.py:793
+#: tiramisu/config.py:807
 msgid "all config in metaconfig must have the same optiondescription"
 msgstr ""
 
-#: tiramisu/config.py:805
+#: tiramisu/config.py:819
 msgid "force_default, force_default_if_same or force_dont_change_value cannot be set with only_config"
 msgstr ""
 
-#: tiramisu/config.py:811
+#: tiramisu/config.py:825
 msgid "force_default and force_dont_change_value cannot be set together"
 msgstr ""
 
@@ -156,143 +156,143 @@ msgstr ""
 msgid "invalid properties type {0} for {1}, must be a tuple"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:145
+#: tiramisu/option/baseoption.py:148
 msgid "params defined for a callback function but no callback defined yet for option {0}"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:150
+#: tiramisu/option/baseoption.py:153
 msgid "a callback is already set for option {0}, cannot set another one's"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:277
+#: tiramisu/option/baseoption.py:280
 msgid "cannot serialize Option, only in OptionDescription"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:363
+#: tiramisu/option/baseoption.py:366
 msgid "'{0}' ({1}) object attribute '{2}' is read-only"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:528 tiramisu/option/baseoption.py:571
+#: tiramisu/option/baseoption.py:545 tiramisu/option/baseoption.py:588
 msgid "invalid value for option {0}: {1}"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:541
+#: tiramisu/option/baseoption.py:558
 msgid "do_validation for {0}: error in value"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:547
+#: tiramisu/option/baseoption.py:564
 msgid "do_validation for {0}: warning in value"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:557
+#: tiramisu/option/baseoption.py:574
 msgid "do_validation for {0}: error in consistency"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:561
+#: tiramisu/option/baseoption.py:578
 msgid "do_validation for {0}: warning in consistency"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:565
+#: tiramisu/option/baseoption.py:582
 msgid "warning on the value of the option {0}: {1}"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:583 tiramisu/option/baseoption.py:592
+#: tiramisu/option/baseoption.py:600 tiramisu/option/baseoption.py:609
 msgid "invalid value {0} for option {1} which must be a list"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:598
+#: tiramisu/option/baseoption.py:615
 msgid "invalid value {0} for option {1} which must be a list of list"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:651
+#: tiramisu/option/baseoption.py:668
 msgid "'{0}' ({1}) cannot add consistency, option is read-only"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:663
+#: tiramisu/option/baseoption.py:680
 msgid "unknow parameter {0} in consistency"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:670
+#: tiramisu/option/baseoption.py:687
 msgid "consistency must be set with an option"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:673 tiramisu/option/baseoption.py:680
+#: tiramisu/option/baseoption.py:690 tiramisu/option/baseoption.py:697
 msgid "almost one option in consistency is in a dynoptiondescription but not all"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:676
+#: tiramisu/option/baseoption.py:693
 msgid "option in consistency must be in same dynoptiondescription"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:683
+#: tiramisu/option/baseoption.py:700
 msgid "cannot add consistency with itself"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:685
+#: tiramisu/option/baseoption.py:702
 msgid "every options in consistency must be multi or none"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:689
+#: tiramisu/option/baseoption.py:706
 msgid "consistency {0} not available for this option"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:717
+#: tiramisu/option/baseoption.py:735
 msgid "same value for {0} and {1}, should be different"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:719
+#: tiramisu/option/baseoption.py:737
 msgid "same value for {0} and {1}, must be different"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:776
+#: tiramisu/option/baseoption.py:794
 msgid "default value not allowed if option: {0} is calculated"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:798
+#: tiramisu/option/baseoption.py:816
 msgid "malformed requirements type for option: {0}, must be a dict"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:804
+#: tiramisu/option/baseoption.py:822
 msgid "malformed requirements for option: {0} unknown keys {1}, must only {2}"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:815
+#: tiramisu/option/baseoption.py:833
 msgid "malformed requirements for option: {0} require must have option, expected and action keys"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:819
+#: tiramisu/option/baseoption.py:837
 msgid "malformed requirements for option: {0} action cannot be force_store_value"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:824
+#: tiramisu/option/baseoption.py:842
 msgid "malformed requirements for option: {0} inverse must be boolean"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:828
+#: tiramisu/option/baseoption.py:846
 msgid "malformed requirements for option: {0} transitive must be boolean"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:832
+#: tiramisu/option/baseoption.py:850
 msgid "malformed requirements for option: {0} same_action must be boolean"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:836
+#: tiramisu/option/baseoption.py:854
 msgid "malformed requirements must be an option in option {0}"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:839
+#: tiramisu/option/baseoption.py:857
 msgid "malformed requirements option {0} must not be a multi for {1}"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:846
+#: tiramisu/option/baseoption.py:864
 msgid "malformed requirements second argument must be valid for option {0}: {1}"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:851
+#: tiramisu/option/baseoption.py:869
 msgid "inconsistency in action types for option: {0} action: {1}"
 msgstr ""
 
-#: tiramisu/option/baseoption.py:879
+#: tiramisu/option/baseoption.py:897
 msgid "malformed symlinkoption must be an option for symlink {0}"
 msgstr ""
 
@@ -316,7 +316,7 @@ msgstr ""
 msgid "callback of master's option shall not refered a slave's ones"
 msgstr ""
 
-#: tiramisu/option/masterslave.py:258
+#: tiramisu/option/masterslave.py:259
 msgid "invalid len for the slave: {0} which has {1} as master"
 msgstr ""
 
@@ -410,7 +410,7 @@ msgid "invalid port"
 msgstr ""
 
 #: tiramisu/option/option.py:293
-msgid "invalid port, must be an between {0} and {1}"
+msgid "invalid port, must be an integer between {0} and {1}"
 msgstr ""
 
 #: tiramisu/option/option.py:306
@@ -605,7 +605,7 @@ msgstr ""
 msgid "permissive must be a tuple"
 msgstr ""
 
-#: tiramisu/setting.py:508 tiramisu/value.py:426
+#: tiramisu/setting.py:508 tiramisu/value.py:437
 msgid "invalid generic owner {0}"
 msgstr ""
 
@@ -617,52 +617,56 @@ msgstr ""
 msgid "option '{0}' has requirement's property error: {1} {2}"
 msgstr ""
 
-#: tiramisu/storage/__init__.py:48
+#: tiramisu/storage/__init__.py:49
 msgid "storage_type is already set, cannot rebind it"
 msgstr ""
 
-#: tiramisu/storage/__init__.py:59
+#: tiramisu/storage/__init__.py:60
 msgid "cannot import the storage {0}"
 msgstr ""
 
-#: tiramisu/storage/__init__.py:90
+#: tiramisu/storage/__init__.py:93
 msgid "option {0} not already exists in storage {1}"
 msgstr ""
 
-#: tiramisu/storage/dictionary/option.py:99
+#: tiramisu/storage/__init__.py:128
+msgid "unable to get storages:"
+msgstr ""
+
+#: tiramisu/storage/dictionary/option.py:96
 msgid "invalid default_multi value {0} for option {1}: {2}"
 msgstr ""
 
-#: tiramisu/storage/dictionary/option.py:141
-#: tiramisu/storage/sqlalchemy/option.py:434 tiramisu/value.py:490
+#: tiramisu/storage/dictionary/option.py:138
+#: tiramisu/storage/sqlalchemy/option.py:431 tiramisu/value.py:501
 msgid "information's item not found: {0}"
 msgstr ""
 
-#: tiramisu/storage/dictionary/option.py:362
-#: tiramisu/storage/sqlalchemy/option.py:478
+#: tiramisu/storage/dictionary/option.py:359
+#: tiramisu/storage/sqlalchemy/option.py:475
 msgid "no option for path {0}"
 msgstr ""
 
-#: tiramisu/storage/dictionary/option.py:368
-#: tiramisu/storage/sqlalchemy/option.py:485
+#: tiramisu/storage/dictionary/option.py:365
+#: tiramisu/storage/sqlalchemy/option.py:482
 msgid "no option {0} found"
 msgstr ""
 
-#: tiramisu/storage/dictionary/option.py:417
+#: tiramisu/storage/dictionary/option.py:414
 msgid "cannot find dynpath"
 msgstr ""
 
-#: tiramisu/storage/dictionary/option.py:507
-#: tiramisu/storage/sqlalchemy/option.py:630
+#: tiramisu/storage/dictionary/option.py:504
+#: tiramisu/storage/sqlalchemy/option.py:627
 msgid "suffix and context needed if it's a dyn option"
 msgstr ""
 
-#: tiramisu/storage/dictionary/option.py:520
+#: tiramisu/storage/dictionary/option.py:517
 msgid "{0} instance has no attribute '_readonly'"
 msgstr ""
 
-#: tiramisu/storage/dictionary/option.py:534
-#: tiramisu/storage/sqlalchemy/option.py:660
+#: tiramisu/storage/dictionary/option.py:531
+#: tiramisu/storage/sqlalchemy/option.py:657
 msgid "unknown Option {0} in OptionDescription {1}"
 msgstr ""
 
@@ -683,51 +687,51 @@ msgstr ""
 msgid "optiondescription has no value"
 msgstr ""
 
-#: tiramisu/value.py:325
+#: tiramisu/value.py:329
 msgid "you should only set value with config"
 msgstr ""
 
-#: tiramisu/value.py:395
+#: tiramisu/value.py:406
 msgid "owner only avalaible for an option"
 msgstr ""
 
-#: tiramisu/value.py:433
+#: tiramisu/value.py:444
 msgid "no value for {0} cannot change owner to {1}"
 msgstr ""
 
-#: tiramisu/value.py:531
+#: tiramisu/value.py:542
 msgid "can force cache only if cache is actived in config"
 msgstr ""
 
-#: tiramisu/value.py:570
+#: tiramisu/value.py:581
 msgid "{0} is already a Multi "
 msgstr ""
 
-#: tiramisu/value.py:636
+#: tiramisu/value.py:651
 msgid "cannot append a value on a multi option {0} which is a slave"
 msgstr ""
 
-#: tiramisu/value.py:655
+#: tiramisu/value.py:675
 msgid "cannot sort multi option {0} if master or slave"
 msgstr ""
 
-#: tiramisu/value.py:659
+#: tiramisu/value.py:679
 msgid "cmp is not permitted in python v3 or greater"
 msgstr ""
 
-#: tiramisu/value.py:668
+#: tiramisu/value.py:688
 msgid "cannot reverse multi option {0} if master or slave"
 msgstr ""
 
-#: tiramisu/value.py:676
+#: tiramisu/value.py:696
 msgid "cannot insert multi option {0} if master or slave"
 msgstr ""
 
-#: tiramisu/value.py:684
+#: tiramisu/value.py:709
 msgid "cannot extend multi option {0} if master or slave"
 msgstr ""
 
-#: tiramisu/value.py:712
+#: tiramisu/value.py:741
 msgid "cannot pop a value on a multi option {0} which is a slave"
 msgstr ""