diff --git a/doc/variable/README.md b/doc/variable/README.md
index 30d4f147..50f2e4b2 100644
--- a/doc/variable/README.md
+++ b/doc/variable/README.md
@@ -254,3 +254,22 @@ Pour définir le [mode](../mode.md) :
```
```
+
+## Les variables qui fournissent des valeurs
+
+Il peut être intéressant de retrouver facilement des variables sans connaitre le chemin complet mais en utilisant le contenu du paramètre "provider".
+C'est particulièrement utile si un service peut être fournit par plusieurs services. Les variables n'auront donc pas le même nom. Utiliser ce paramètre, permet donc de retrouver facilement la variable.
+
+Pour déclarer :
+
+```
+
+```
+
+Dans le code de l'application, on pourra retrouver le chemin de la variable en faisant :
+
+```
+print(await config.information.get('provider:my_function'))
+```
+
+Pour les variables inclusent dans une famille dynamique, le chemin de la variable sera un template comme ceci "rougail.family_{suffix}.my_variable_{suffix}". Il vous suffit de remplacer "{suffix}" par le suffix voulu de la famille dynamique.
diff --git a/src/rougail/annotator/property.py b/src/rougail/annotator/property.py
index d3fed9e0..fbc958cd 100644
--- a/src/rougail/annotator/property.py
+++ b/src/rougail/annotator/property.py
@@ -56,11 +56,13 @@ class Annotator(Walk):
# hidden variable is also frozen
if isinstance(variable, self.objectspace.variable) and variable.hidden is True and \
variable.name != self.objectspace.rougailconfig['auto_freeze_variable']:
- if not variable.auto_freeze:
+ if not variable.auto_freeze and \
+ not hasattr(variable, 'provider'):
variable.frozen = True
if not variable.auto_save and \
not variable.auto_freeze and \
- 'force_default_on_freeze' not in vars(variable):
+ 'force_default_on_freeze' not in vars(variable) and \
+ not hasattr(variable, 'provider'):
variable.force_default_on_freeze = True
if not hasattr(variable, 'properties'):
variable.properties = []
diff --git a/src/rougail/tiramisureflector.py b/src/rougail/tiramisureflector.py
index 6e14ff7d..041200e5 100644
--- a/src/rougail/tiramisureflector.py
+++ b/src/rougail/tiramisureflector.py
@@ -28,8 +28,10 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
from json import dumps
from os.path import isfile
+from .i18n import _
from .annotator import CONVERT_OPTION
from .objspace import RootRougailObject
+from .error import DictConsistencyError
class BaseElt: # pylint: disable=R0903
@@ -213,7 +215,11 @@ class Common:
self.populate_attrib()
self.populate_informations()
if hasattr(self.elt, 'provider'):
- self.providers['provider:' + self.elt.provider] = self.dynamic_path
+ name = 'provider:' + self.elt.provider
+ if name in self.providers:
+ msg = f'provider {name} declare multiple time'
+ raise DictConsistencyError(msg, 79, self.elt.xmlfiles)
+ self.providers[name] = self.dynamic_path
return self.option_name
def populate_attrib(self):
@@ -303,7 +309,7 @@ class Common:
return 'ParamSuffix()'
if param.type == 'index':
return 'ParamIndex()'
- raise Exception(f'unknown type {param.type}') # pragma: no cover
+ raise Exception(_(f'unknown type {param.type}')) # pragma: no cover
@staticmethod
def build_option_param(param,
diff --git a/tests/dictionaries/01base_file_include_content/result/etc/dir/incfile b/tests/dictionaries/01base_file_include_content/result/etc/dir/incfile
deleted file mode 100644
index d907505b..00000000
--- a/tests/dictionaries/01base_file_include_content/result/etc/dir/incfile
+++ /dev/null
@@ -1 +0,0 @@
-non
diff --git a/tests/dictionaries/01base_provider_hidden/00-base.xml b/tests/dictionaries/01base_provider_hidden/00-base.xml
new file mode 100644
index 00000000..ee9e3c32
--- /dev/null
+++ b/tests/dictionaries/01base_provider_hidden/00-base.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+ 0.527
+
+
+ 0.527
+
+
+
+
diff --git a/tests/dictionaries/01base_provider_hidden/__init__.py b/tests/dictionaries/01base_provider_hidden/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/01base_provider_hidden/makedict/after.json b/tests/dictionaries/01base_provider_hidden/makedict/after.json
new file mode 100644
index 00000000..005c64da
--- /dev/null
+++ b/tests/dictionaries/01base_provider_hidden/makedict/after.json
@@ -0,0 +1,12 @@
+{
+ "rougail.general.float": {
+ "owner": "default",
+ "value": 0.527
+ },
+ "rougail.general.float_multi": {
+ "owner": "default",
+ "value": [
+ 0.527
+ ]
+ }
+}
diff --git a/tests/dictionaries/01base_provider_hidden/makedict/base.json b/tests/dictionaries/01base_provider_hidden/makedict/base.json
new file mode 100644
index 00000000..99e81271
--- /dev/null
+++ b/tests/dictionaries/01base_provider_hidden/makedict/base.json
@@ -0,0 +1,6 @@
+{
+ "rougail.general.float": 0.527,
+ "rougail.general.float_multi": [
+ 0.527
+ ]
+}
diff --git a/tests/dictionaries/01base_provider_hidden/makedict/before.json b/tests/dictionaries/01base_provider_hidden/makedict/before.json
new file mode 100644
index 00000000..005c64da
--- /dev/null
+++ b/tests/dictionaries/01base_provider_hidden/makedict/before.json
@@ -0,0 +1,12 @@
+{
+ "rougail.general.float": {
+ "owner": "default",
+ "value": 0.527
+ },
+ "rougail.general.float_multi": {
+ "owner": "default",
+ "value": [
+ 0.527
+ ]
+ }
+}
diff --git a/tests/dictionaries/01base_provider_hidden/tiramisu/base.py b/tests/dictionaries/01base_provider_hidden/tiramisu/base.py
new file mode 100644
index 00000000..61aa363f
--- /dev/null
+++ b/tests/dictionaries/01base_provider_hidden/tiramisu/base.py
@@ -0,0 +1,22 @@
+from importlib.machinery import SourceFileLoader as _SourceFileLoader
+from importlib.util import spec_from_loader as _spec_from_loader, module_from_spec as _module_from_spec
+class func:
+ pass
+_loader = _SourceFileLoader('func', 'tests/dictionaries/../eosfunc/test.py')
+_spec = _spec_from_loader(_loader.name, _loader)
+_func = _module_from_spec(_spec)
+_loader.exec_module(_func)
+for function in dir(_func):
+ if function.startswith('_'):
+ continue
+ setattr(func, function, getattr(_func, function))
+try:
+ from tiramisu3 import *
+except:
+ from tiramisu import *
+option_3 = FloatOption(name="float", doc="Description", default=0.527, properties=frozenset({"hidden", "mandatory", "normal"}))
+option_4 = FloatOption(name="float_multi", doc="Description", multi=True, default=[0.527], default_multi=0.527, properties=frozenset({"mandatory", "normal"}))
+option_2 = OptionDescription(name="general", doc="general", children=[option_3, option_4], properties=frozenset({"normal"}))
+option_1 = OptionDescription(name="rougail", doc="rougail", children=[option_2])
+option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1])
+option_0.impl_set_information('provider:float', "rougail.general.float")