diff --git a/src/rougail/annotator/fill.py b/src/rougail/annotator/fill.py
index 017c5946a..5d9b328bd 100644
--- a/src/rougail/annotator/fill.py
+++ b/src/rougail/annotator/fill.py
@@ -32,7 +32,7 @@ from rougail.annotator.target import TargetAnnotator
from rougail.annotator.param import ParamAnnotator
-CALC_MULTI = ('calc_value', 'calc_list', 'get_range', 'calc_val_first_value', 'unbound_filename', 'zone_information', 'get_certificates', 'nsd_filename', 'get_linked_configuration')
+CALC_MULTI = ('calc_value', 'calc_list', 'get_range', 'calc_val_first_value', 'unbound_filename', 'zone_information', 'get_certificates', 'nsd_filename', 'get_linked_configuration', 'get_internal_zones', 'nsd_concat_lists', 'get_internal_info_in_zone')
class Annotator(TargetAnnotator, ParamAnnotator):
diff --git a/src/rougail/annotator/param.py b/src/rougail/annotator/param.py
index c316bb967..64e7a2e04 100644
--- a/src/rougail/annotator/param.py
+++ b/src/rougail/annotator/param.py
@@ -102,8 +102,11 @@ class ParamAnnotator:
if param.type == 'suffix':
for target in obj.target:
if not self.objectspace.paths.variable_is_dynamic(target.name.path):
+ target_name = target.name
+ if isinstance(target_name, self.objectspace.variable):
+ target_name = target_name.name
msg = _(f'"{param.type}" parameter cannot be set with target '
- f'"{target.name}" which is not a dynamic variable')
+ f'"{target_name}" which is not a dynamic variable')
raise DictConsistencyError(msg, 53, obj.xmlfiles)
elif param.type == 'index':
for target in obj.target:
diff --git a/src/rougail/convert.py b/src/rougail/convert.py
index 3d2fe1d3b..87458c042 100644
--- a/src/rougail/convert.py
+++ b/src/rougail/convert.py
@@ -86,6 +86,7 @@ class RougailConvert:
)
self.output = TiramisuReflector(rougailobjspace,
functions_file,
+ rougailconfig['internal_functions'],
).get_text() + '\n'
@staticmethod
diff --git a/src/rougail/data/rougail.dtd b/src/rougail/data/rougail.dtd
index 0829d5cf2..64a311640 100644
--- a/src/rougail/data/rougail.dtd
+++ b/src/rougail/data/rougail.dtd
@@ -90,7 +90,6 @@
-
diff --git a/src/rougail/objspace.py b/src/rougail/objspace.py
index 3be267288..ea48373c3 100644
--- a/src/rougail/objspace.py
+++ b/src/rougail/objspace.py
@@ -179,6 +179,7 @@ class RougailObjSpace:
self.space,
namespace,
redefine_variables,
+ False,
)
def _xml_parse(self, # pylint: disable=R0913
@@ -187,10 +188,15 @@ class RougailObjSpace:
space,
namespace,
redefine_variables,
+ is_dynamic,
) -> None:
# var to check unique family name in a XML file
family_names = []
for child in document:
+ if is_dynamic:
+ is_sub_dynamic = True
+ else:
+ is_sub_dynamic = document.attrib.get('dynamic') is not None
if not isinstance(child.tag, str):
# doesn't proceed the XML commentaries
continue
@@ -225,6 +231,7 @@ class RougailObjSpace:
document,
variableobj,
space,
+ is_sub_dynamic,
)
self.add_to_tree_structure(variableobj,
space,
@@ -237,6 +244,7 @@ class RougailObjSpace:
variableobj,
namespace,
redefine_variables,
+ is_sub_dynamic,
)
def get_variableobj(self,
@@ -472,6 +480,7 @@ class RougailObjSpace:
document,
variableobj,
space,
+ is_dynamic,
):
"""Fill self.paths attributes
"""
@@ -488,7 +497,7 @@ class RougailObjSpace:
self.paths.add_variable(namespace,
variableobj.name,
space.path,
- document.attrib.get('dynamic') is not None,
+ is_dynamic,
variableobj,
leader,
)
diff --git a/src/rougail/path.py b/src/rougail/path.py
index a4a38762f..a9b984296 100644
--- a/src/rougail/path.py
+++ b/src/rougail/path.py
@@ -125,6 +125,8 @@ class Path:
) -> str: # pylint: disable=C0111
"""Add a new variable (with path)
"""
+ if name == 'hostname_' and not is_dynamic:
+ raise Exception('pffff')
if '.' not in name:
full_path = '.'.join([family, name])
if namespace == self.variable_namespace:
diff --git a/src/rougail/template/base.py b/src/rougail/template/base.py
index 19f12d39b..2f167743c 100644
--- a/src/rougail/template/base.py
+++ b/src/rougail/template/base.py
@@ -236,6 +236,7 @@ class RougailBaseTemplate:
def patch_template(self,
filename: str,
+ templates_dir: str,
) -> None:
"""Apply patch to a template
"""
@@ -251,7 +252,7 @@ class RougailBaseTemplate:
msg = _(f"Error applying patch: '{patch_file}'\n"
f"To reproduce and fix this error {patch_cmd_err}")
self.log.error(_(msg))
- copy(join(self.templates_dir, filename), self.tmp_dir)
+ copy(join(templates_dir, filename), self.tmp_dir)
def prepare_template(self,
filename: str,
@@ -263,7 +264,7 @@ class RougailBaseTemplate:
if not isdir(self.tmp_dir):
raise TemplateError(_(f'cannot find tmp_dir {self.tmp_dir}'))
copy(join(templates_dir, filename), self.tmp_dir)
- self.patch_template(filename)
+ self.patch_template(filename, templates_dir)
def instance_file(self,
filevar: Dict,
diff --git a/src/rougail/template/systemd.py b/src/rougail/template/systemd.py
index 338963e2c..61c6ce203 100644
--- a/src/rougail/template/systemd.py
+++ b/src/rougail/template/systemd.py
@@ -84,7 +84,7 @@ class RougailSystemdTemplate(RougailBaseTemplate):
) -> tuple:
source = filevar['source']
if not isfile(source): # pragma: no cover
- raise FileNotFound(_(f"File {source} does not exist."))
+ raise FileNotFound(_(f'Source file "{source}" does not exist in {", ".join(self.templates_dir)}'))
tmp_file = join(self.tmp_dir, source)
#self.instance_file(fill, 'files')
if variable:
@@ -102,7 +102,7 @@ class RougailSystemdTemplate(RougailBaseTemplate):
) -> tuple:
source = filevar['source']
if not isfile(source): # pragma: no cover
- raise FileNotFound(_(f"File {source} does not exist."))
+ raise FileNotFound(_(f'Override source file "{source}" does not exist in {", ".join(self.templates_dir)}'))
tmp_file = join(self.tmp_dir, source)
service_name = filevar['name']
destfile = f'/systemd/system/{service_name}.{service_type}.d/rougail.conf'
diff --git a/src/rougail/tiramisureflector.py b/src/rougail/tiramisureflector.py
index 3ee27dcab..6e14ff7d5 100644
--- a/src/rougail/tiramisureflector.py
+++ b/src/rougail/tiramisureflector.py
@@ -32,12 +32,6 @@ from .annotator import CONVERT_OPTION
from .objspace import RootRougailObject
-class Root(): # pylint: disable=R0903
- """Root classes
- """
- path = '.'
-
-
class BaseElt: # pylint: disable=R0903
"""Base element
"""
@@ -52,6 +46,7 @@ class TiramisuReflector:
def __init__(self,
objectspace,
funcs_paths,
+ internal_functions,
):
self.index = 0
self.text = []
@@ -73,6 +68,9 @@ class TiramisuReflector:
" continue",
" setattr(func, function, getattr(_func, function))",
])
+ if internal_functions:
+ for func in internal_functions:
+ self.text.append(f"setattr(func, '{func}', {func})")
self.text.extend(["try:",
" from tiramisu3 import *",
"except:",
@@ -86,8 +84,11 @@ class TiramisuReflector:
def make_tiramisu_objects(self) -> None:
"""make tiramisu objects
"""
+ providers = {}
baseelt = BaseElt()
self.set_name(baseelt)
+ dynamic_path = ''
+ dynamic = False
basefamily = Family(baseelt,
self.text,
self.objectspace,
@@ -95,7 +96,12 @@ class TiramisuReflector:
for elt in self.reorder_family():
self.populate_family(basefamily,
elt,
+ providers,
+ dynamic,
+ dynamic_path,
)
+ basefamily.elt.information = providers
+ basefamily.populate_informations()
self.baseelt = baseelt
def reorder_family(self):
@@ -115,6 +121,9 @@ class TiramisuReflector:
def populate_family(self,
parent_family,
elt,
+ providers,
+ dynamic,
+ dynamic_path,
):
"""Populate family
"""
@@ -123,11 +132,21 @@ class TiramisuReflector:
self.text,
self.objectspace,
)
+ if not dynamic_path:
+ dynamic_path = elt.name
+ else:
+ dynamic_path = dynamic_path + '.' + elt.name
+ if dynamic or hasattr(elt, 'suffixes'):
+ dynamic_path += '{suffix}'
+ dynamic = True
parent_family.add(family)
for children in vars(elt).values():
if isinstance(children, self.objectspace.family):
self.populate_family(family,
children,
+ providers,
+ dynamic,
+ dynamic_path,
)
continue
if isinstance(children, dict):
@@ -139,13 +158,21 @@ class TiramisuReflector:
continue
if isinstance(child, self.objectspace.variable):
self.set_name(child)
+ sub_dynamic_path = dynamic_path + '.' + child.name
+ if dynamic:
+ sub_dynamic_path += '{suffix}'
family.add(Variable(child,
self.text,
self.objectspace,
+ providers,
+ sub_dynamic_path,
))
else:
self.populate_family(family,
child,
+ providers,
+ dynamic,
+ dynamic_path,
)
def set_name(self,
@@ -185,6 +212,8 @@ class Common:
self.option_name = self.elt.reflector_name
self.populate_attrib()
self.populate_informations()
+ if hasattr(self.elt, 'provider'):
+ self.providers['provider:' + self.elt.provider] = self.dynamic_path
return self.option_name
def populate_attrib(self):
@@ -239,7 +268,11 @@ class Common:
"""
if not hasattr(self.elt, 'information'):
return
- for key, value in vars(self.elt.information).items():
+ if isinstance(self.elt.information, dict):
+ informations = self.elt.information
+ else:
+ informations = vars(self.elt.information)
+ for key, value in informations.items():
if key == 'xmlfiles':
continue
if isinstance(value, str):
@@ -297,7 +330,11 @@ class Variable(Common):
elt,
text,
objectspace,
+ providers,
+ dynamic_path,
):
+ self.providers = providers
+ self.dynamic_path = dynamic_path
super().__init__(elt, text, objectspace)
self.object_type = CONVERT_OPTION[elt.type]['opttype']
diff --git a/tests/dictionaries/01base_provider/00-base.xml b/tests/dictionaries/01base_provider/00-base.xml
new file mode 100644
index 000000000..7f1f67693
--- /dev/null
+++ b/tests/dictionaries/01base_provider/00-base.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
+ 0.527
+
+
+ 0.527
+
+
+
+
diff --git a/tests/dictionaries/01base_provider/__init__.py b/tests/dictionaries/01base_provider/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/dictionaries/01base_provider/makedict/after.json b/tests/dictionaries/01base_provider/makedict/after.json
new file mode 100644
index 000000000..005c64daf
--- /dev/null
+++ b/tests/dictionaries/01base_provider/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/makedict/base.json b/tests/dictionaries/01base_provider/makedict/base.json
new file mode 100644
index 000000000..99e81271b
--- /dev/null
+++ b/tests/dictionaries/01base_provider/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/makedict/before.json b/tests/dictionaries/01base_provider/makedict/before.json
new file mode 100644
index 000000000..005c64daf
--- /dev/null
+++ b/tests/dictionaries/01base_provider/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/tiramisu/base.py b/tests/dictionaries/01base_provider/tiramisu/base.py
new file mode 100644
index 000000000..ba16b03e2
--- /dev/null
+++ b/tests/dictionaries/01base_provider/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({"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")
diff --git a/tests/dictionaries/22provider_dynamic/00-base.xml b/tests/dictionaries/22provider_dynamic/00-base.xml
new file mode 100644
index 000000000..a651a8fe5
--- /dev/null
+++ b/tests/dictionaries/22provider_dynamic/00-base.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+ val1
+ val2
+
+
+
+
+
+
+
diff --git a/tests/dictionaries/22provider_dynamic/__init__.py b/tests/dictionaries/22provider_dynamic/__init__.py
new file mode 100644
index 000000000..e69de29bb
diff --git a/tests/dictionaries/22provider_dynamic/makedict/after.json b/tests/dictionaries/22provider_dynamic/makedict/after.json
new file mode 100644
index 000000000..4201ce973
--- /dev/null
+++ b/tests/dictionaries/22provider_dynamic/makedict/after.json
@@ -0,0 +1,17 @@
+{
+ "rougail.general.varname": {
+ "owner": "default",
+ "value": [
+ "val1",
+ "val2"
+ ]
+ },
+ "rougail.dynval1.vardynval1": {
+ "owner": "default",
+ "value": null
+ },
+ "rougail.dynval2.vardynval2": {
+ "owner": "default",
+ "value": null
+ }
+}
diff --git a/tests/dictionaries/22provider_dynamic/makedict/base.json b/tests/dictionaries/22provider_dynamic/makedict/base.json
new file mode 100644
index 000000000..f3dfb5918
--- /dev/null
+++ b/tests/dictionaries/22provider_dynamic/makedict/base.json
@@ -0,0 +1,8 @@
+{
+ "rougail.general.varname": [
+ "val1",
+ "val2"
+ ],
+ "rougail.dynval1.vardynval1": null,
+ "rougail.dynval2.vardynval2": null
+}
diff --git a/tests/dictionaries/22provider_dynamic/makedict/before.json b/tests/dictionaries/22provider_dynamic/makedict/before.json
new file mode 100644
index 000000000..4201ce973
--- /dev/null
+++ b/tests/dictionaries/22provider_dynamic/makedict/before.json
@@ -0,0 +1,17 @@
+{
+ "rougail.general.varname": {
+ "owner": "default",
+ "value": [
+ "val1",
+ "val2"
+ ]
+ },
+ "rougail.dynval1.vardynval1": {
+ "owner": "default",
+ "value": null
+ },
+ "rougail.dynval2.vardynval2": {
+ "owner": "default",
+ "value": null
+ }
+}
diff --git a/tests/dictionaries/22provider_dynamic/tiramisu/base.py b/tests/dictionaries/22provider_dynamic/tiramisu/base.py
new file mode 100644
index 000000000..3f9b08ac8
--- /dev/null
+++ b/tests/dictionaries/22provider_dynamic/tiramisu/base.py
@@ -0,0 +1,24 @@
+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 *
+from rougail.tiramisu import ConvertDynOptionDescription
+option_3 = StrOption(name="varname", doc="No change", multi=True, default=['val1', 'val2'], default_multi="val1", properties=frozenset({"mandatory", "normal"}))
+option_2 = OptionDescription(name="general", doc="general", children=[option_3], properties=frozenset({"normal"}))
+option_5 = StrOption(name="vardyn", doc="No change", properties=frozenset({"normal"}))
+option_4 = ConvertDynOptionDescription(name="dyn", doc="dyn", suffixes=Calculation(func.calc_value, Params((ParamOption(option_3, notraisepropertyerror=True)))), children=[option_5], properties=frozenset({"normal"}))
+option_1 = OptionDescription(name="rougail", doc="rougail", children=[option_2, option_4])
+option_0 = OptionDescription(name="baseoption", doc="baseoption", children=[option_1])
+option_0.impl_set_information('provider:dyn', "rougail.dyn{suffix}.vardyn{suffix}")