diff --git a/src/rougail/annotator/constrainte.py b/src/rougail/annotator/constrainte.py
index 8e9e4d7c..f00f3b49 100644
--- a/src/rougail/annotator/constrainte.py
+++ b/src/rougail/annotator/constrainte.py
@@ -46,8 +46,6 @@ class ConstrainteAnnotator:
self.remove_constraints()
def convert_auto_freeze(self): # pylint: disable=C0111
- if not hasattr(self.objectspace.space, 'variables'):
- return
def _convert_auto_freeze(variable, namespace):
if variable.auto_freeze:
if namespace != Config['variable_namespace']:
@@ -129,52 +127,14 @@ class ConstrainteAnnotator:
xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
raise DictConsistencyError(_(f'param is mandatory for a valid_enum of variable "{check.target}" in {xmlfiles}'), 4)
variable = self.objectspace.paths.get_variable_obj(check.target)
- values = self.load_params_in_valid_enum(check.param,
- variable.name,
- variable.type,
- )
self._set_valid_enum(variable,
- values,
- variable.type,
- check.target,
- check.xmlfiles,
+ check,
)
remove_indexes.append(idx)
remove_indexes.sort(reverse=True)
for idx in remove_indexes:
del self.objectspace.space.constraints.check[idx]
- def load_params_in_valid_enum(self,
- params,
- variable_name,
- variable_type,
- ):
- has_variable = None
- values = []
- for param in params:
- if param.type == 'variable':
- if has_variable is not None:
- xmlfiles = self.objectspace.display_xmlfiles(param.xmlfiles)
- raise DictConsistencyError(_(f'only one "variable" parameter is allowed for valid_enum of variable "{variable_name}" in {xmlfiles}'), 5)
- has_variable = True
- variable = self.objectspace.paths.get_variable_obj(param.text)
- if not variable.multi:
- xmlfiles = self.objectspace.display_xmlfiles(param.xmlfiles)
- raise DictConsistencyError(_(f'only multi "variable" parameter is allowed for valid_enum of variable "{variable_name}" in {xmlfiles}'), 6)
- values = param.text
- else:
- if has_variable:
- xmlfiles = self.objectspace.display_xmlfiles(param.xmlfiles)
- raise DictConsistencyError(_(f'only one parameter is allowed for valid_enum of variable "{variable_name}" in {xmlfiles}'), 7)
- if not hasattr(param, 'text'):
- if param.type == 'number':
- xmlfiles = self.objectspace.display_xmlfiles(param.xmlfiles)
- raise DictConsistencyError(_(f'param type is number, so value is mandatory for valid_enum of variable "{variable_name}" in {xmlfiles}'), 8)
- values.append(None)
- else:
- values.append(param.text)
- return values
-
def check_change_warning(self):
#convert level to "warnings_only"
for check in self.objectspace.space.constraints.check:
@@ -201,7 +161,8 @@ class ConstrainteAnnotator:
def check_params_target(self):
for condition in self.objectspace.space.constraints.condition:
if not hasattr(condition, 'target'):
- raise DictConsistencyError(_('target is mandatory in condition'), 9)
+ xmlfiles = self.objectspace.display_xmlfiles(condition.xmlfiles)
+ raise DictConsistencyError(_(f'target is mandatory in a condition for source "{condition.source}" in {xmlfiles}'), 9)
for target in condition.target:
if target.type.endswith('list') and condition.name not in ['disabled_if_in', 'disabled_if_not_in']:
xmlfiles = self.objectspace.display_xmlfiles(target.xmlfiles)
@@ -217,9 +178,10 @@ class ConstrainteAnnotator:
try:
target_names = [normalize_family(name) for name in target.name.split('.')]
target.name = self.objectspace.paths.get_variable_path('.'.join(target_names), namespace)
- except DictConsistencyError:
+ except DictConsistencyError as err:
# for optional variable
- pass
+ if not target.optional or err.errno != 42:
+ raise err
elif target.type == 'family':
try:
target_names = [normalize_family(name) for name in target.name.split('.')]
@@ -305,9 +267,17 @@ class ConstrainteAnnotator:
remove_conditions = []
for condition_idx, condition in enumerate(self.objectspace.space.constraints.condition):
namespace = condition.namespace
- condition.source = self.objectspace.paths.get_variable_path(condition.source, namespace, allow_source=True)
+ condition.source, suffix = self.objectspace.paths.get_variable_path(condition.source,
+ namespace,
+ allow_source=True,
+ with_suffix=True,
+ )
+ if suffix:
+ xmlfiles = self.objectspace.display_xmlfiles(condition.xmlfiles)
+ raise DictConsistencyError(_(f'the source "{condition.source}" in condition cannot be a dynamic variable in {xmlfiles}'), 20)
src_variable = self.objectspace.paths.get_variable_obj(condition.source)
valid_enum = None
+ # FIXME only string?
if condition.source in self.valid_enums and self.valid_enums[condition.source]['type'] == 'string':
valid_enum = self.valid_enums[condition.source]['values']
if valid_enum is not None:
@@ -319,7 +289,6 @@ class ConstrainteAnnotator:
for idx in remove_param:
del condition.param[idx]
if condition.param == []:
- remove_targets = []
for target in condition.target:
leader_or_variable, variables = self._get_family_variables_from_target(target)
if condition.name == 'disabled_if_not_in':
@@ -330,11 +299,7 @@ class ConstrainteAnnotator:
variable.frozen = True
variable.force_default_on_freeze = True
elif condition.name == 'mandatory_if_not_in':
- variable.mandatory = True
- remove_targets = list(set(remove_targets))
- remove_targets.sort(reverse=True)
- for target_idx in remove_targets:
- condition.target.pop(target_idx)
+ leader_or_variable.mandatory = True
remove_conditions.append(condition_idx)
remove_conditions = list(set(remove_conditions))
remove_conditions.sort(reverse=True)
@@ -342,11 +307,8 @@ class ConstrainteAnnotator:
self.objectspace.space.constraints.condition.pop(idx)
def remove_condition_with_empty_target(self):
- remove_conditions = []
- for condition_idx, condition in enumerate(self.objectspace.space.constraints.condition):
- if not condition.target:
- remove_conditions.append(condition_idx)
- remove_conditions = list(set(remove_conditions))
+ # optional target are remove, condition could be empty
+ remove_conditions = [condition_idx for condition_idx, condition in enumerate(self.objectspace.space.constraints.condition) if not condition.target]
remove_conditions.sort(reverse=True)
for idx in remove_conditions:
self.objectspace.space.constraints.condition.pop(idx)
@@ -391,58 +353,72 @@ class ConstrainteAnnotator:
def _set_valid_enum(self,
variable,
- values,
- type_,
- target: str,
- xmlfiles: List[str],
+ check,
):
+ type_ = variable.type
+ target = check.target
# value for choice's variable is mandatory
variable.mandatory = True
# build choice
variable.choice = []
- if isinstance(values, str):
+ variable.type = 'choice'
+
+ has_variable = False
+ values = []
+ for param in check.param:
+ if has_variable:
+ xmlfiles = self.objectspace.display_xmlfiles(param.xmlfiles)
+ raise DictConsistencyError(_(f'only one "variable" parameter is allowed for valid_enum of variable "{variable.name}" in {xmlfiles}'), 5)
+ param_type = type_
+ if param.type == 'variable':
+ has_variable = True
+ param_variable = self.objectspace.paths.get_variable_obj(param.text)
+ if param.optional is True:
+ xmlfiles = self.objectspace.display_xmlfiles(param.xmlfiles)
+ raise DictConsistencyError(_(f'optional parameter in valid_enum for variable "{variable.name}" is not allowed in {xmlfiles}'), 14)
+ if not param_variable.multi:
+ xmlfiles = self.objectspace.display_xmlfiles(param.xmlfiles)
+ raise DictConsistencyError(_(f'only multi "variable" parameter is allowed for valid_enum of variable "{variable.name}" in {xmlfiles}'), 6)
+ param_type = 'calculation'
+ value = param.text
+ else:
+ if 'type' in vars(param) and type_ != param.type:
+ xmlfiles = self.objectspace.display_xmlfiles(param.xmlfiles)
+ raise DictConsistencyError(_(f'parameter in valid_enum has incompatible type "{param.type}" with type of the variable "{variable.name}" ("{type_}") in {xmlfiles}'), 7)
+ if hasattr(param, 'text'):
+ try:
+ value = CONVERT_OPTION[type_].get('func', str)(param.text)
+ except:
+ raise DictConsistencyError(_(f'unable to change type of a valid_enum entry "{param.text}" is not a valid "{type_}" for "{variable.name}"'), 13)
+ else:
+ if param.type == 'number':
+ xmlfiles = self.objectspace.display_xmlfiles(param.xmlfiles)
+ raise DictConsistencyError(_(f'param type is number, so value is mandatory for valid_enum of variable "{variable.name}" in {xmlfiles}'), 8)
+ value = None
+ values.append(value)
choice = self.objectspace.choice(variable.xmlfiles)
- choice.type = 'calculation'
- choice.name = values
+ choice.name = value
+ choice.type = param_type
variable.choice.append(choice)
- else:
+ if has_variable:
+ return
+
+ # FIXME really?
+ if param_type != 'calculation':
self.valid_enums[target] = {'type': type_,
'values': values,
- 'xmlfiles': xmlfiles,
+ 'xmlfiles': check.xmlfiles,
}
- choices = []
- for value in values:
- choice = self.objectspace.choice(variable.xmlfiles)
- try:
- if value is not None:
- choice.name = CONVERT_OPTION[type_].get('func', str)(value)
- else:
- choice.name = value
- except:
- raise DictConsistencyError(_(f'unable to change type of a valid_enum entry "{value}" is not a valid "{type_}" for "{variable.name}"'), 13)
- if choice.name == '':
- choice.name = None
- choices.append(choice.name)
- choice.type = type_
- variable.choice.append(choice)
- # check value or set first choice value has default value
- if hasattr(variable, 'value'):
- for value in variable.value:
- value.type = type_
- try:
- cvalue = CONVERT_OPTION[type_].get('func', str)(value.name)
- except:
- raise DictConsistencyError(_(f'unable to change type of value "{value}" is not a valid "{type_}" for "{variable.name}"'), 14)
- if cvalue not in choices:
- raise DictConsistencyError(_('value "{}" of variable "{}" is not in list of all expected values ({})').format(value.name, variable.name, choices), 15)
- else:
- new_value = self.objectspace.value(variable.xmlfiles)
- new_value.name = choices[0]
- new_value.type = type_
- variable.value = [new_value]
- if not variable.choice:
- raise DictConsistencyError(_('empty valid enum is not allowed for variable {}').format(variable.name), 16)
- variable.type = 'choice'
+ # check value or set first choice value has default value
+ if hasattr(variable, 'value'):
+ for value in variable.value:
+ if value.name not in values:
+ raise DictConsistencyError(_(f'value "{value.name}" of variable "{variable.name}" is not in list of all expected values ({values})'), 15)
+ else:
+ new_value = self.objectspace.value(check.xmlfiles)
+ new_value.name = values[0]
+ new_value.type = type_
+ variable.value = [new_value]
def convert_check(self):
for check in self.objectspace.space.constraints.check:
@@ -452,39 +428,18 @@ class ConstrainteAnnotator:
if not hasattr(check, 'param'):
raise DictConsistencyError(_('{} must have, at least, 1 param').format(name), 17)
for param in check.param:
- if param.type not in ['string', 'number']:
- raise DictConsistencyError(_(f'param in "valid_entier" must not be a "{param.type}"'), 18)
+ if param.type != 'number':
+ xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
+ raise DictConsistencyError(_(f'param in "valid_entier" must be an "integer", not "{param.type}" in {xmlfiles}'), 18)
if param.name == 'mini':
variable.min_number = int(param.text)
elif param.name == 'maxi':
variable.max_number = int(param.text)
else:
- raise DictConsistencyError(_(f'unknown parameter {param.text} in check "valid_entier" for variable {check.target}'), 19)
+ xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
+ raise DictConsistencyError(_(f'unknown parameter "{param.name}" in check "valid_entier" for variable "{check.target}" in {xmlfiles}'), 19)
else:
check_ = self.objectspace.check(variable.xmlfiles)
- if name == 'valid_differ':
- name = 'valid_not_equal'
- elif name == 'valid_network_netmask':
- params_len = 1
- if len(check.param) != params_len:
- xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
- raise DictConsistencyError(_(f'{name} must have {params_len} param in {xmlfiles}'), 20)
- elif name == 'valid_ipnetmask':
- params_len = 1
- if len(check.param) != params_len:
- xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
- raise DictConsistencyError(_(f'{name} must have {params_len} param in {xmlfiles}'), 21)
- name = 'valid_ip_netmask'
- elif name == 'valid_broadcast':
- params_len = 2
- if len(check.param) != params_len:
- xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
- raise DictConsistencyError(_(f'{name} must have {params_len} param in {xmlfiles}'), 22)
- elif name == 'valid_in_network':
- if len(check.param) not in (1, 2):
- params_len = 2
- xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles)
- raise DictConsistencyError(_(f'{name} must have {params_len} param in {xmlfiles}'), 23)
check_.name = name
check_.warnings_only = check.warnings_only
if hasattr(check, 'param'):
@@ -510,7 +465,7 @@ class ConstrainteAnnotator:
#
if fill.name not in self.functions:
xmlfiles = self.objectspace.display_xmlfiles(fill.xmlfiles)
- raise DictConsistencyError(_(f'cannot find fill function {fill.name} in {xmlfiles}'), 25)
+ raise DictConsistencyError(_(f'cannot find fill function "{fill.name}" in {xmlfiles}'), 25)
namespace = fill.namespace
# let's replace the target by the path
@@ -520,7 +475,7 @@ class ConstrainteAnnotator:
)
if suffix is not None:
xmlfiles = self.objectspace.display_xmlfiles(fill.xmlfiles)
- raise DictConsistencyError(_(f'Cannot add fill function to "{fill.target}" only with the suffix "{suffix}" in {xmlfiles}'), 26)
+ raise DictConsistencyError(_(f'Cannot add fill function to "{fill.target}" only for the suffix "{suffix}" in {xmlfiles}'), 26)
variable = self.objectspace.paths.get_variable_obj(fill.target)
value = self.objectspace.value(variable.xmlfiles)
value.type = 'calculation'
@@ -534,7 +489,7 @@ class ConstrainteAnnotator:
if param.type == 'suffix':
if hasattr(param, 'text'):
xmlfiles = self.objectspace.display_xmlfiles(fill.xmlfiles)
- raise DictConsistencyError(_(f"All '{param.type}' variables must not have a value in order to calculate {fill.target} in {xmlfiles}"), 28)
+ raise DictConsistencyError(_(f'"{param.type}" variables must not have a value in order to calculate "{fill.target}" in {xmlfiles}'), 28)
if not self.objectspace.paths.variable_is_dynamic(fill.target):
xmlfiles = self.objectspace.display_xmlfiles(fill.xmlfiles)
raise DictConsistencyError(_(f'Cannot set suffix target to the none dynamic variable "{fill.target}" in {xmlfiles}'), 53)
@@ -570,7 +525,6 @@ class ConstrainteAnnotator:
del self.objectspace.space.constraints.index
del self.objectspace.space.constraints.namespace
del self.objectspace.space.constraints.xmlfiles
- if vars(self.objectspace.space.constraints):
+ if vars(self.objectspace.space.constraints): # pragma: no cover
raise Exception('constraints again?')
del self.objectspace.space.constraints
-
diff --git a/src/rougail/annotator/family.py b/src/rougail/annotator/family.py
index 43d3ceb4..fe4a438b 100644
--- a/src/rougail/annotator/family.py
+++ b/src/rougail/annotator/family.py
@@ -73,6 +73,10 @@ class FamilyAnnotator:
if 'dynamic' in vars(family):
namespace = self.objectspace.paths.get_variable_namespace(family.dynamic)
varpath = self.objectspace.paths.get_variable_path(family.dynamic, namespace)
+ obj = self.objectspace.paths.get_variable_obj(varpath)
+ if not obj.multi:
+ xmlfiles = self.objectspace.display_xmlfiles(family.xmlfiles)
+ raise DictConsistencyError(_(f'dynamic family "{family.name}" must be linked to multi variable in {xmlfiles}'), 16)
family.dynamic = varpath
def annotate_variable(self, variable, family_mode, path, is_follower=False):
diff --git a/src/rougail/path.py b/src/rougail/path.py
index 59899970..9e826c2c 100644
--- a/src/rougail/path.py
+++ b/src/rougail/path.py
@@ -27,43 +27,46 @@ class Path:
self.full_paths_families[name] = full_name
else:
full_name = name
- if full_name in self.families and self.families[full_name]['variableobj'] != variableobj:
- raise DictConsistencyError(_(f'Duplicate family name {name}'), 37)
+ if full_name in self.families and self.families[full_name]['variableobj'] != variableobj: # pragma: no cover
+ raise DictConsistencyError(_(f'Duplicate family name "{name}"'), 37)
self.families[full_name] = dict(name=name,
namespace=namespace,
variableobj=variableobj,
)
+ def _get_family(self,
+ name: str,
+ namespace: str=None,
+ ):
+ # if main namespace, get full_path
+ if '.' not in name and namespace in [None, Config['variable_namespace']] and name in self.full_paths_families:
+ name = self.full_paths_families[name]
+ dico = self.families[name]
+ if namespace and dico['namespace'] != Config['variable_namespace'] and namespace != dico['namespace']:
+ raise DictConsistencyError(_(f'A family located in the "{dico["namespace"]}" namespace shall not be used in the "{namespace}" namespace'), 38)
+ return dico
+
def get_family_path(self,
name: str,
- current_namespace: str,
+ namespace: str,
) -> str: # pylint: disable=C0111
- #name = normalize_family(name)
- if '.' not in name and current_namespace == Config['variable_namespace'] and name in self.full_paths_families:
- name = self.full_paths_families[name]
- if current_namespace is None: # pragma: no cover
- raise OperationError('current_namespace must not be None')
- dico = self.families[name]
- if dico['namespace'] != Config['variable_namespace'] and current_namespace != dico['namespace']:
- raise DictConsistencyError(_(f'A family located in the "{dico["namespace"]}" namespace shall not be used in the "{current_namespace}" namespace'), 38)
- return dico['name']
+ return self._get_family(name,
+ namespace,
+ )['name']
def get_family_obj(self,
name: str,
) -> 'Family': # pylint: disable=C0111
- if '.' not in name and name in self.full_paths_families:
- name = self.full_paths_families[name]
- if name not in self.families:
- raise DictConsistencyError(_('unknown family {}').format(name), 39)
- dico = self.families[name]
- return dico['variableobj']
+ return self._get_family(name)['variableobj']
def family_is_defined(self,
- name: str,
- ) -> str: # pylint: disable=C0111
- if '.' not in name and name not in self.families and name in self.full_paths_families:
+ name: str,
+ ) -> str: # pylint: disable=C0111
+ try:
+ self._get_family(name)
return True
- return name in self.families
+ except KeyError:
+ return False
# Leadership
def set_leader(self,
@@ -74,24 +77,11 @@ class Path:
) -> None: # pylint: disable=C0111
# need rebuild path and move object in new path
old_path = namespace + '.' + leader_family_name + '.' + name
- dico = self._get_variable(old_path)
- del self.variables[old_path]
new_path = namespace + '.' + leader_family_name + '.' + leader_name + '.' + name
- self.add_variable(namespace,
- new_path,
- dico['family'],
- False,
- dico['variableobj'],
- )
+ self.variables[new_path] = self.variables.pop(old_path)
+ self.variables[new_path]['leader'] = leader_name
if namespace == Config['variable_namespace']:
self.full_paths_variables[name] = new_path
- else:
- name = new_path
- dico = self._get_variable(name)
- if dico['leader'] != None:
- raise DictConsistencyError(_('Already defined leader {} for variable'
- ' {}'.format(dico['leader'], name)), 40)
- dico['leader'] = leader_name
def get_leader(self, name): # pylint: disable=C0111
return self._get_variable(name)['leader']
@@ -109,14 +99,13 @@ class Path:
self.full_paths_variables[name] = full_name
else:
full_name = name
- if namespace == Config['variable_namespace']:
- name = name.rsplit('.', 1)[1]
self.variables[full_name] = dict(name=name,
family=family,
namespace=namespace,
leader=None,
is_dynamic=is_dynamic,
- variableobj=variableobj)
+ variableobj=variableobj,
+ )
def get_variable_name(self,
name,
@@ -152,17 +141,13 @@ class Path:
)
else:
dico = self._get_variable(name)
- if not allow_source:
- if dico['namespace'] not in [Config['variable_namespace'], 'services'] and current_namespace != dico['namespace']:
+ if not allow_source and dico['namespace'] not in [Config['variable_namespace'], 'services'] and current_namespace != dico['namespace']:
raise DictConsistencyError(_(f'A variable located in the "{dico["namespace"]}" namespace shall not be used in the "{current_namespace}" namespace'), 41)
- if '.' in dico['name']:
- value = dico['name']
- else:
- list_path = [dico['namespace'], dico['family']]
- if dico['leader'] is not None:
- list_path.append(dico['leader'])
- list_path.append(dico['name'])
- value = '.'.join(list_path)
+ list_path = [dico['namespace'], dico['family']]
+ if dico['leader'] is not None:
+ list_path.append(dico['leader'])
+ list_path.append(dico['name'])
+ value = '.'.join(list_path)
if with_suffix:
return value, suffix
return value
@@ -184,24 +169,16 @@ class Path:
with_suffix: bool=False,
) -> str:
if name not in self.variables:
- if name not in self.variables:
- if '.' not in name and name in self.full_paths_variables:
- name = self.full_paths_variables[name]
- if name not in self.variables:
- for var_name, variable in self.variables.items():
- if variable['is_dynamic'] and name.startswith(var_name):
- if not with_suffix:
- raise Exception('This option is dynamic, should use "with_suffix" attribute')
- return variable, name[len(var_name):]
- if '.' not in name:
- for var_name, path in self.full_paths_variables.items():
- if name.startswith(var_name):
- variable = self.variables[self.full_paths_variables[var_name]]
- if variable['is_dynamic']:
- if not with_suffix:
- raise Exception('This option is dynamic, should use "with_suffix" attribute')
- return variable, name[len(var_name):]
- raise DictConsistencyError(_('unknown option {}').format(name), 42)
+ if '.' not in name and name in self.full_paths_variables:
+ name = self.full_paths_variables[name]
+ elif with_suffix:
+ for var_name, full_path in self.full_paths_variables.items():
+ if name.startswith(var_name):
+ variable = self._get_variable(full_path)
+ if variable['is_dynamic']:
+ return variable, name[len(var_name):]
+ if name not in self.variables:
+ raise DictConsistencyError(_('unknown option {}').format(name), 42)
if with_suffix:
return self.variables[name], None
return self.variables[name]
diff --git a/src/rougail/template.py b/src/rougail/template.py
index 60e70c08..95821697 100644
--- a/src/rougail/template.py
+++ b/src/rougail/template.py
@@ -17,8 +17,8 @@ from Cheetah.NameMapper import NotFound as CheetahNotFound
try:
from tiramisu3 import Config
- from tiramisu3.error import PropertiesOptionError
-except:
+ from tiramisu3.error import PropertiesOptionError # pragma: no cover
+except: # pragma: no cover
from tiramisu import Config
from tiramisu.error import PropertiesOptionError
@@ -32,28 +32,6 @@ log = logging.getLogger(__name__)
log.addHandler(logging.NullHandler())
-class IsDefined:
- """
- filtre permettant de ne pas lever d'exception au cas où
- la variable Creole n'est pas définie
- """
- def __init__(self, context):
- self.context = context
-
- def __call__(self, varname):
- if '.' in varname:
- splitted_var = varname.split('.')
- if len(splitted_var) != 2:
- msg = _("Group variables must be of type leader.follower")
- raise KeyError(msg)
- leader, follower = splitted_var
- if leader in self.context:
- return follower in self.context[leader].follower.keys()
- return False
- else:
- return varname in self.context
-
-
@classmethod
def cl_compile(kls, *args, **kwargs):
kwargs['compilerSettings'] = {'directiveStartToken' : '%',
@@ -83,8 +61,7 @@ class CheetahTemplate(ChtTemplate):
):
"""Initialize Creole CheetahTemplate
"""
- extra_context = {'is_defined' : IsDefined(context),
- 'normalize_family': normalize_family,
+ extra_context = {'normalize_family': normalize_family,
'rougail_filename': destfilename
}
if variable:
@@ -93,7 +70,7 @@ class CheetahTemplate(ChtTemplate):
file=filename,
searchList=[context, eosfunc, extra_context])
- # FORK of Cheetah fonction, do not replace '\\' by '/'
+ # FORK of Cheetah function, do not replace '\\' by '/'
def serverSidePath(self,
path=None,
normpath=normpath,
@@ -105,119 +82,103 @@ class CheetahTemplate(ChtTemplate):
path = self
if path:
return normpath(abspath(path))
-# return normpath(abspath(path.replace("\\", '/')))
- elif hasattr(self, '_filePath') and self._filePath:
+# original code return normpath(abspath(path.replace("\\", '/')))
+ elif hasattr(self, '_filePath') and self._filePath: # pragma: no cover
return normpath(abspath(self._filePath))
- else:
+ else: # pragma: no cover
return None
-class CreoleLeader:
- def __init__(self, value, follower=None, index=None):
- """
- On rend la variable itérable pour pouvoir faire:
- for ip in iplist:
- print(ip.network)
- print(ip.netmask)
- print(ip)
- index is used for CreoleLint
- """
+class CreoleValue:
+ def __str__(self):
+ return str(self._value)
+
+
+class CreoleLeaderIndex(CreoleValue):
+ def __init__(self,
+ value,
+ follower,
+ index,
+ ) -> None:
self._value = value
- if follower is not None:
- self.follower = follower
- else:
- self.follower = {}
+ self._follower = follower
self._index = index
def __getattr__(self, name):
- """Get follower variable or attribute of leader value.
+ if name not in self._follower:
+ raise AttributeError()
+ value = self._follower[name]
+ if isinstance(value, PropertiesOptionError):
+ raise AttributeError()
+ return value
- If the attribute is a name of a follower variable, return its value.
- Otherwise, returns the requested attribute of leader value.
- """
- if name in self.follower:
- value = self.follower[name]
- if isinstance(value, PropertiesOptionError):
- raise AttributeError()
- return value
- else:
- return getattr(self._value, name)
+ def __lt__(self, value):
+ return self._value.__lt__(value)
+
+ def __le__(self, value):
+ return self._value.__le__(value)
+
+ def __eq__(self, value):
+ return self._value.__eq__(value)
+
+ def __ne__(self, value):
+ return self._value.__ne__(value)
+
+ def __gt__(self, value):
+ return self._value.__gt__(value)
+
+ def __ge__(self, value):
+ return self._value >= value
+
+ def __add__(self, value):
+ return self._value.__add__(value)
+
+ def __radd__(self, value):
+ return value + self._value
+
+
+class CreoleLeader(CreoleValue):
+ def __init__(self,
+ value,
+ ) -> None:
+ self._value = value
+ self._follower = {}
def __getitem__(self, index):
"""Get a leader.follower at requested index.
"""
- ret = {}
- for key, values in self.follower.items():
- ret[key] = values[index]
- return CreoleLeader(self._value[index], ret, index)
+ followers = {key: values[index] for key, values in self._follower.items()}
+ return CreoleLeaderIndex(self._value[index],
+ followers,
+ index,
+ )
def __iter__(self):
"""Iterate over leader.follower.
Return synchronised value of leader.follower.
"""
- for i in range(len(self._value)):
- ret = {}
- for key, values in self.follower.items():
- ret[key] = values[i]
- yield CreoleLeader(self._value[i], ret, i)
+ for index in range(len(self._value)):
+ yield self.__getitem__(index)
def __len__(self):
- """Delegate to leader value
- """
return len(self._value)
- def __repr__(self):
- """Show CreoleLeader as dictionary.
+ def __contains__(self, value):
+ return self._value.__contains__(value)
- The leader value is stored under 'value' key.
- The followers are stored under 'follower' key.
- """
- return repr({'value': self._value, 'follower': self.follower})
-
- def __eq__(self, value):
- return value == self._value
-
- def __ne__(self, value):
- return value != self._value
-
- def __lt__(self, value):
- return self._value < value
-
- def __le__(self, value):
- return self._value <= value
-
- def __gt__(self, value):
- return self._value > value
-
- def __ge__(self, value):
- return self._value >= value
-
- def __str__(self):
- """Delegate to leader value
- """
- return str(self._value)
-
- def __add__(self, val):
- return self._value.__add__(val)
-
- def __radd__(self, val):
- return val + self._value
-
- def __contains__(self, item):
- return item in self._value
-
- async def add_follower(self, config, name, path):
- if isinstance(self._value, list):
- values = []
- for idx in range(len(self._value)):
- try:
- values.append(await config.option(path, idx).value.get())
- except PropertiesOptionError as err:
- values.append(err)
- else:
- raise Exception('hu?')
- self.follower[name] = values
+ async def add_follower(self,
+ config,
+ name: str,
+ path: str,
+ ):
+ self._follower[name] = []
+ for index in range(len(self._value)):
+ try:
+ value = await config.option(path, index).value.get()
+ except PropertiesOptionError as err:
+ value = err
+ self._follower[name].append(value)
class CreoleExtra:
@@ -229,9 +190,6 @@ class CreoleExtra:
key: str) -> Any:
return self.suboption[key]
- def __repr__(self):
- return self.suboption.__str__()
-
def __iter__(self):
return iter(self.suboption.values())
@@ -260,7 +218,8 @@ class CreoleTemplateEngine:
self.rougail_variables_dict = {}
async def load_eole_variables_rougail(self,
- optiondescription):
+ optiondescription,
+ ):
for option in await optiondescription.list('all'):
if await option.option.isoptiondescription():
if await option.option.isleadership():
@@ -270,8 +229,9 @@ class CreoleTemplateEngine:
self.rougail_variables_dict[await suboption.option.name()] = leader
else:
await leader.add_follower(self.config,
- await suboption.option.name(),
- await suboption.option.path())
+ await suboption.option.name(),
+ await suboption.option.path(),
+ )
else:
await self.load_eole_variables_rougail(option)
else:
@@ -292,8 +252,9 @@ class CreoleTemplateEngine:
leader_name = await suboption.option.name()
else:
await leader.add_follower(self.config,
- await suboption.option.name(),
- await suboption.option.path())
+ await suboption.option.name(),
+ await suboption.option.path(),
+ )
variables[leader_name] = leader
else:
subfamilies = await self.load_eole_variables(await variable.option.name(),
@@ -320,7 +281,7 @@ class CreoleTemplateEngine:
log.info(_("Patching template '{filename}' with '{patch_file}'"))
rel_patch_file = relpath(patch_file, tmp_dir)
ret = call(patch_cmd + patch_no_debug + ['-i', rel_patch_file])
- if ret:
+ if ret: # pragma: no cover
patch_cmd_err = ' '.join(patch_cmd + ['-i', rel_patch_file])
log.error(_(f"Error applying patch: '{rel_patch_file}'\nTo reproduce and fix this error {patch_cmd_err}"))
copy(join(self.distrib_dir, filename), tmp_dir)
@@ -355,10 +316,10 @@ class CreoleTemplateEngine:
variable,
)
data = str(cheetah_template)
- except CheetahNotFound as err:
+ except CheetahNotFound as err: # pragma: no cover
varname = err.args[0][13:-1]
raise TemplateError(_(f"Error: unknown variable used in template {source} to {destfilename} : {varname}"))
- except Exception as err:
+ except Exception as err: # pragma: no cover
raise TemplateError(_(f"Error while instantiating template {source} to {destfilename}: {err}"))
with open(destfilename, 'w') as file_h:
@@ -424,7 +385,7 @@ class CreoleTemplateEngine:
for fill_obj in await fills.list('all'):
fill = await fill_obj.value.dict()
filename = fill['source']
- if not isfile(filename):
+ if not isfile(filename): # pragma: no cover
raise FileNotFound(_(f"File {filename} does not exist."))
if fill.get('activate', False):
self.instance_file(fill,
diff --git a/src/rougail/tiramisureflector.py b/src/rougail/tiramisureflector.py
index 512d62b8..86ebf65e 100644
--- a/src/rougail/tiramisureflector.py
+++ b/src/rougail/tiramisureflector.py
@@ -7,7 +7,7 @@ from .error import LoaderError
from .annotator import ERASED_ATTRIBUTES, CONVERT_OPTION
-FUNC_TO_DICT = ['valid_not_equal']
+FUNC_TO_DICT = []
FORCE_INFORMATIONS = ['help', 'test', 'separator', 'manage']
ATTRIBUTES_ORDER = ('name', 'doc', 'default', 'multi')
@@ -395,7 +395,7 @@ class Variable(Common):
self.attrib['default'].append(value)
if not self.is_leader:
self.attrib['default_multi'] = value
- elif isinstance(value, (int, float)):
+ elif isinstance(value, (int, float)) or value is None:
self.attrib['default'].append(value)
else:
self.attrib['default'].append("'" + value + "'")
diff --git a/tests/dictionaries/10check_base/00-base.xml b/tests/dictionaries/10check_base/00-base.xml
index 40b7ebfa..c5786883 100644
--- a/tests/dictionaries/10check_base/00-base.xml
+++ b/tests/dictionaries/10check_base/00-base.xml
@@ -11,8 +11,8 @@
- 0
- 100
+ 0
+ 100
diff --git a/tests/dictionaries/10check_optional/tiramisu/base.py b/tests/dictionaries/10check_optional/tiramisu/base.py
index 2e3a50e3..6294b7cd 100644
--- a/tests/dictionaries/10check_optional/tiramisu/base.py
+++ b/tests/dictionaries/10check_optional/tiramisu/base.py
@@ -10,7 +10,7 @@ except:
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = StrOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='b')
option_5 = IntOption(properties=frozenset({'normal'}), name='int2', doc='No change', multi=False)
-option_4 = IntOption(properties=frozenset({'normal'}), validators=[Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_5, notraisepropertyerror=False, todict=True)), kwargs={}), warnings_only=False)], name='int', doc='No change', multi=False)
+option_4 = IntOption(properties=frozenset({'normal'}), validators=[Calculation(func.valid_differ, Params((ParamSelfOption(), ParamOption(option_5, notraisepropertyerror=False, todict=False)), kwargs={}), warnings_only=False)], name='int', doc='No change', multi=False)
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4, option_5])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
diff --git a/tests/dictionaries/10check_valid_differ/tiramisu/base.py b/tests/dictionaries/10check_valid_differ/tiramisu/base.py
index 932d3384..534ded43 100644
--- a/tests/dictionaries/10check_valid_differ/tiramisu/base.py
+++ b/tests/dictionaries/10check_valid_differ/tiramisu/base.py
@@ -9,7 +9,7 @@ except:
from tiramisu import *
from rougail.tiramisu import ConvertDynOptionDescription
option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif1', doc='No change', multi=False, default='non', values=('oui', 'non'))
-option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), validators=[Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=True)), kwargs={}), warnings_only=False)], name='mode_conteneur_actif', doc='No change', multi=False, default='oui', values=('oui', 'non'))
+option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), validators=[Calculation(func.valid_differ, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=False)), kwargs={}), warnings_only=False)], name='mode_conteneur_actif', doc='No change', multi=False, default='oui', values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
diff --git a/tests/dictionaries/10check_valid_differ_add/tiramisu/base.py b/tests/dictionaries/10check_valid_differ_add/tiramisu/base.py
index 2aac2277..3105aeea 100644
--- a/tests/dictionaries/10check_valid_differ_add/tiramisu/base.py
+++ b/tests/dictionaries/10check_valid_differ_add/tiramisu/base.py
@@ -11,7 +11,7 @@ from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='oui', values=('oui', 'non'))
option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif1', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_5 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif2', doc='No change', multi=False, default='non', values=('oui', 'non'))
-option_6 = StrOption(properties=frozenset({'mandatory', 'normal'}), validators=[Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=True)), kwargs={}), warnings_only=False), Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=True)), kwargs={}), warnings_only=False), Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_5, notraisepropertyerror=False, todict=True)), kwargs={}), warnings_only=False)], name='mode_conteneur_actif3', doc='No change', multi=False, default='oui')
+option_6 = StrOption(properties=frozenset({'mandatory', 'normal'}), validators=[Calculation(func.valid_differ, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=False)), kwargs={}), warnings_only=False), Calculation(func.valid_differ, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=False)), kwargs={}), warnings_only=False), Calculation(func.valid_differ, Params((ParamSelfOption(), ParamOption(option_5, notraisepropertyerror=False, todict=False)), kwargs={}), warnings_only=False)], name='mode_conteneur_actif3', doc='No change', multi=False, default='oui')
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4, option_5, option_6])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
diff --git a/tests/dictionaries/10check_valid_differ_removecheck/tiramisu/base.py b/tests/dictionaries/10check_valid_differ_removecheck/tiramisu/base.py
index 889721ea..fc7dc232 100644
--- a/tests/dictionaries/10check_valid_differ_removecheck/tiramisu/base.py
+++ b/tests/dictionaries/10check_valid_differ_removecheck/tiramisu/base.py
@@ -11,7 +11,7 @@ from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='oui', values=('oui', 'non'))
option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif1', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_5 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif2', doc='No change', multi=False, default='non', values=('oui', 'non'))
-option_6 = StrOption(properties=frozenset({'mandatory', 'normal'}), validators=[Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=True)), kwargs={}), warnings_only=False), Calculation(func.valid_not_equal, Params((ParamSelfOption(), ParamOption(option_5, notraisepropertyerror=False, todict=True)), kwargs={}), warnings_only=False)], name='mode_conteneur_actif3', doc='No change', multi=False, default='oui')
+option_6 = StrOption(properties=frozenset({'mandatory', 'normal'}), validators=[Calculation(func.valid_differ, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=False)), kwargs={}), warnings_only=False), Calculation(func.valid_differ, Params((ParamSelfOption(), ParamOption(option_5, notraisepropertyerror=False, todict=False)), kwargs={}), warnings_only=False)], name='mode_conteneur_actif3', doc='No change', multi=False, default='oui')
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4, option_5, option_6])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
diff --git a/tests/dictionaries/10check_valid_ipnetmask/tiramisu/base.py b/tests/dictionaries/10check_valid_ipnetmask/tiramisu/base.py
index 74b4048f..a014f254 100644
--- a/tests/dictionaries/10check_valid_ipnetmask/tiramisu/base.py
+++ b/tests/dictionaries/10check_valid_ipnetmask/tiramisu/base.py
@@ -10,7 +10,7 @@ except:
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='oui', values=('oui', 'non'))
option_4 = IPOption(private_only=True, warnings_only=True, properties=frozenset({'basic', 'mandatory'}), name='adresse_ip_eth0', doc='Adresse IP de la carte', multi=False)
-option_5 = NetmaskOption(properties=frozenset({'basic', 'mandatory'}), validators=[Calculation(func.valid_ip_netmask, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=False)), kwargs={}), warnings_only=True)], name='adresse_netmask_eth0', doc='Masque de sous réseau de la carte', multi=False)
+option_5 = NetmaskOption(properties=frozenset({'basic', 'mandatory'}), validators=[Calculation(func.valid_ipnetmask, Params((ParamSelfOption(), ParamOption(option_4, notraisepropertyerror=False, todict=False)), kwargs={}), warnings_only=True)], name='adresse_netmask_eth0', doc='Masque de sous réseau de la carte', multi=False)
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'basic'}), children=[option_3, option_4, option_5])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
diff --git a/tests/dictionaries/10leadership_append/makedict/base.json b/tests/dictionaries/10leadership_append/makedict/base.json
index 346b748d..9e804f6a 100644
--- a/tests/dictionaries/10leadership_append/makedict/base.json
+++ b/tests/dictionaries/10leadership_append/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": "non", "rougail.general1.leader.leader": [], "rougail.general1.leader.follower1": [], "rougail.general1.leader.follower2": [], "rougail.general1.leader.follower3": []}
+{"rougail.general.mode_conteneur_actif": "non", "rougail.general1.leader.leader": []}
diff --git a/tests/dictionaries/10leadership_auto/makedict/base.json b/tests/dictionaries/10leadership_auto/makedict/base.json
index 330c847d..107d7b1c 100644
--- a/tests/dictionaries/10leadership_auto/makedict/base.json
+++ b/tests/dictionaries/10leadership_auto/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": "non", "rougail.general.leader.leader": [], "rougail.general.leader.follower1": [], "rougail.general.leader.follower2": [], "rougail.general.leader.follower3": []}
+{"rougail.general.mode_conteneur_actif": "non", "rougail.general.leader.leader": []}
diff --git a/tests/dictionaries/10leadership_autoleader/makedict/base.json b/tests/dictionaries/10leadership_autoleader/makedict/base.json
index 3ff8a0ae..107d7b1c 100644
--- a/tests/dictionaries/10leadership_autoleader/makedict/base.json
+++ b/tests/dictionaries/10leadership_autoleader/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": "non", "rougail.general.leader.leader": [], "rougail.general.leader.follower1": [], "rougail.general.leader.follower2": []}
+{"rougail.general.mode_conteneur_actif": "non", "rougail.general.leader.leader": []}
diff --git a/tests/dictionaries/10leadership_autoleader_expert/makedict/base.json b/tests/dictionaries/10leadership_autoleader_expert/makedict/base.json
index 903d2481..1691edbc 100644
--- a/tests/dictionaries/10leadership_autoleader_expert/makedict/base.json
+++ b/tests/dictionaries/10leadership_autoleader_expert/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": "non", "rougail.leadermode.leader.leader": [], "rougail.leadermode.leader.follower1": [], "rougail.leadermode.leader.follower2": []}
+{"rougail.general.mode_conteneur_actif": "non", "rougail.leadermode.leader.leader": []}
diff --git a/tests/dictionaries/10leadership_autosaveexpert/makedict/base.json b/tests/dictionaries/10leadership_autosaveexpert/makedict/base.json
index 3ff8a0ae..107d7b1c 100644
--- a/tests/dictionaries/10leadership_autosaveexpert/makedict/base.json
+++ b/tests/dictionaries/10leadership_autosaveexpert/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": "non", "rougail.general.leader.leader": [], "rougail.general.leader.follower1": [], "rougail.general.leader.follower2": []}
+{"rougail.general.mode_conteneur_actif": "non", "rougail.general.leader.leader": []}
diff --git a/tests/dictionaries/10leadership_familyaccent/makedict/base.json b/tests/dictionaries/10leadership_familyaccent/makedict/base.json
index 3ff8a0ae..107d7b1c 100644
--- a/tests/dictionaries/10leadership_familyaccent/makedict/base.json
+++ b/tests/dictionaries/10leadership_familyaccent/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": "non", "rougail.general.leader.leader": [], "rougail.general.leader.follower1": [], "rougail.general.leader.follower2": []}
+{"rougail.general.mode_conteneur_actif": "non", "rougail.general.leader.leader": []}
diff --git a/tests/dictionaries/10leadership_leader_hidden/makedict/base.json b/tests/dictionaries/10leadership_leader_hidden/makedict/base.json
index 903d2481..1691edbc 100644
--- a/tests/dictionaries/10leadership_leader_hidden/makedict/base.json
+++ b/tests/dictionaries/10leadership_leader_hidden/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": "non", "rougail.leadermode.leader.leader": [], "rougail.leadermode.leader.follower1": [], "rougail.leadermode.leader.follower2": []}
+{"rougail.general.mode_conteneur_actif": "non", "rougail.leadermode.leader.leader": []}
diff --git a/tests/dictionaries/10leadership_leader_hidden_if_in/makedict/base.json b/tests/dictionaries/10leadership_leader_hidden_if_in/makedict/base.json
index 903d2481..1691edbc 100644
--- a/tests/dictionaries/10leadership_leader_hidden_if_in/makedict/base.json
+++ b/tests/dictionaries/10leadership_leader_hidden_if_in/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": "non", "rougail.leadermode.leader.leader": [], "rougail.leadermode.leader.follower1": [], "rougail.leadermode.leader.follower2": []}
+{"rougail.general.mode_conteneur_actif": "non", "rougail.leadermode.leader.leader": []}
diff --git a/tests/dictionaries/10leadership_leadermandatory/makedict/base.json b/tests/dictionaries/10leadership_leadermandatory/makedict/base.json
index 3ff8a0ae..107d7b1c 100644
--- a/tests/dictionaries/10leadership_leadermandatory/makedict/base.json
+++ b/tests/dictionaries/10leadership_leadermandatory/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": "non", "rougail.general.leader.leader": [], "rougail.general.leader.follower1": [], "rougail.general.leader.follower2": []}
+{"rougail.general.mode_conteneur_actif": "non", "rougail.general.leader.leader": []}
diff --git a/tests/dictionaries/10leadership_mandatory/makedict/base.json b/tests/dictionaries/10leadership_mandatory/makedict/base.json
index 3ff8a0ae..107d7b1c 100644
--- a/tests/dictionaries/10leadership_mandatory/makedict/base.json
+++ b/tests/dictionaries/10leadership_mandatory/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": "non", "rougail.general.leader.leader": [], "rougail.general.leader.follower1": [], "rougail.general.leader.follower2": []}
+{"rougail.general.mode_conteneur_actif": "non", "rougail.general.leader.leader": []}
diff --git a/tests/dictionaries/10leadership_mandatoryfollower/makedict/base.json b/tests/dictionaries/10leadership_mandatoryfollower/makedict/base.json
index c61597eb..e40cb9a7 100644
--- a/tests/dictionaries/10leadership_mandatoryfollower/makedict/base.json
+++ b/tests/dictionaries/10leadership_mandatoryfollower/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": "oui", "rougail.general.nut_monitor_netmask.nut_monitor_netmask": [], "rougail.general.nut_monitor_netmask.nut_monitor_host": []}
+{"rougail.general.mode_conteneur_actif": "oui", "rougail.general.nut_monitor_netmask.nut_monitor_netmask": []}
diff --git a/tests/dictionaries/10leadership_multi/makedict/base.json b/tests/dictionaries/10leadership_multi/makedict/base.json
index 3e5c28c6..1b4d93cb 100644
--- a/tests/dictionaries/10leadership_multi/makedict/base.json
+++ b/tests/dictionaries/10leadership_multi/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": "non", "rougail.general1.leader.leader": [], "rougail.general1.leader.follower1": [], "rougail.general1.leader.follower2": [], "rougail.general1.leader1.leader1": [], "rougail.general1.leader1.follower11": [], "rougail.general1.leader1.follower21": []}
+{"rougail.general.mode_conteneur_actif": "non", "rougail.general1.leader.leader": [], "rougail.general1.leader1.leader1": []}
diff --git a/tests/dictionaries/10load_frozenifnotin/00-base.xml b/tests/dictionaries/10load_frozenifnotin/00-base.xml
new file mode 100644
index 00000000..dc295858
--- /dev/null
+++ b/tests/dictionaries/10load_frozenifnotin/00-base.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+ non
+
+
+ non
+
+
+ non
+
+
+
+
+
+
+ oui
+ mode_conteneur_actif
+ mode_conteneur_actif2
+
+
+
+
diff --git a/tests/dictionaries/10check_valid_differ_add/tiramisu/__init__.py b/tests/dictionaries/10load_frozenifnotin/__init__.py
similarity index 100%
rename from tests/dictionaries/10check_valid_differ_add/tiramisu/__init__.py
rename to tests/dictionaries/10load_frozenifnotin/__init__.py
diff --git a/tests/dictionaries/10load_frozenifnotin/makedict/base.json b/tests/dictionaries/10load_frozenifnotin/makedict/base.json
new file mode 100644
index 00000000..25db64a2
--- /dev/null
+++ b/tests/dictionaries/10load_frozenifnotin/makedict/base.json
@@ -0,0 +1 @@
+{"rougail.general.condition": "non", "rougail.general.mode_conteneur_actif": "non", "rougail.general.mode_conteneur_actif2": "non"}
diff --git a/tests/dictionaries/10check_valid_differ_removecheck/tiramisu/__init__.py b/tests/dictionaries/10load_frozenifnotin/tiramisu/__init__.py
similarity index 100%
rename from tests/dictionaries/10check_valid_differ_removecheck/tiramisu/__init__.py
rename to tests/dictionaries/10load_frozenifnotin/tiramisu/__init__.py
diff --git a/tests/dictionaries/10load_frozenifnotin/tiramisu/base.py b/tests/dictionaries/10load_frozenifnotin/tiramisu/base.py
new file mode 100644
index 00000000..1c54443d
--- /dev/null
+++ b/tests/dictionaries/10load_frozenifnotin/tiramisu/base.py
@@ -0,0 +1,16 @@
+from importlib.machinery import SourceFileLoader
+func = SourceFileLoader('func', 'tests/dictionaries/../eosfunc/test.py').load_module()
+for key, value in dict(locals()).items():
+ if key != ['SourceFileLoader', 'func']:
+ setattr(func, key, value)
+try:
+ from tiramisu3 import *
+except:
+ from tiramisu import *
+from rougail.tiramisu import ConvertDynOptionDescription
+option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='condition', doc='No change', multi=False, default='non', values=('oui', 'non'))
+option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal', Calculation(calc_value, Params(ParamValue('hidden'), kwargs={'condition': ParamOption(option_3, todict=True), 'expected': ParamValue('oui'), 'reverse_condition': ParamValue(True)})), Calculation(calc_value, Params(ParamValue('frozen'), kwargs={'condition': ParamOption(option_3, todict=True), 'expected': ParamValue('oui'), 'reverse_condition': ParamValue(True)})), Calculation(calc_value, Params(ParamValue('force_default_on_freeze'), kwargs={'condition': ParamOption(option_3, todict=True), 'expected': ParamValue('oui'), 'reverse_condition': ParamValue(True)}))}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
+option_5 = ChoiceOption(properties=frozenset({'mandatory', 'normal', Calculation(calc_value, Params(ParamValue('hidden'), kwargs={'condition': ParamOption(option_3, todict=True), 'expected': ParamValue('oui'), 'reverse_condition': ParamValue(True)})), Calculation(calc_value, Params(ParamValue('frozen'), kwargs={'condition': ParamOption(option_3, todict=True), 'expected': ParamValue('oui'), 'reverse_condition': ParamValue(True)})), Calculation(calc_value, Params(ParamValue('force_default_on_freeze'), kwargs={'condition': ParamOption(option_3, todict=True), 'expected': ParamValue('oui'), 'reverse_condition': ParamValue(True)}))}), name='mode_conteneur_actif2', doc='No change', multi=False, default='non', values=('oui', 'non'))
+option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4, option_5])
+option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
+option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
diff --git a/tests/dictionaries/10load_frozenifnotin_noexist/00-base.xml b/tests/dictionaries/10load_frozenifnotin_noexist/00-base.xml
new file mode 100644
index 00000000..fa5cf511
--- /dev/null
+++ b/tests/dictionaries/10load_frozenifnotin_noexist/00-base.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+ tous
+
+
+ non
+
+
+ non
+
+
+
+
+
+
+
+ tous
+ authentifié
+ aucun
+
+
+ oui
+ non
+ mode_conteneur_actif
+ mode_conteneur_actif2
+
+
+
+
+
diff --git a/tests/dictionaries/10check_valid_ipnetmask/tiramisu/__init__.py b/tests/dictionaries/10load_frozenifnotin_noexist/__init__.py
similarity index 100%
rename from tests/dictionaries/10check_valid_ipnetmask/tiramisu/__init__.py
rename to tests/dictionaries/10load_frozenifnotin_noexist/__init__.py
diff --git a/tests/dictionaries/10load_frozenifnotin_noexist/makedict/base.json b/tests/dictionaries/10load_frozenifnotin_noexist/makedict/base.json
new file mode 100644
index 00000000..3e41cfc3
--- /dev/null
+++ b/tests/dictionaries/10load_frozenifnotin_noexist/makedict/base.json
@@ -0,0 +1 @@
+{"rougail.general.condition": "tous", "rougail.general.mode_conteneur_actif": "non", "rougail.general.mode_conteneur_actif2": "non"}
diff --git a/tests/dictionaries/80valid_enum_multi_param/errno_7 b/tests/dictionaries/10load_frozenifnotin_noexist/tiramisu/__init__.py
similarity index 100%
rename from tests/dictionaries/80valid_enum_multi_param/errno_7
rename to tests/dictionaries/10load_frozenifnotin_noexist/tiramisu/__init__.py
diff --git a/tests/dictionaries/10load_frozenifnotin_noexist/tiramisu/base.py b/tests/dictionaries/10load_frozenifnotin_noexist/tiramisu/base.py
new file mode 100644
index 00000000..099f9f5b
--- /dev/null
+++ b/tests/dictionaries/10load_frozenifnotin_noexist/tiramisu/base.py
@@ -0,0 +1,16 @@
+from importlib.machinery import SourceFileLoader
+func = SourceFileLoader('func', 'tests/dictionaries/../eosfunc/test.py').load_module()
+for key, value in dict(locals()).items():
+ if key != ['SourceFileLoader', 'func']:
+ setattr(func, key, value)
+try:
+ from tiramisu3 import *
+except:
+ from tiramisu import *
+from rougail.tiramisu import ConvertDynOptionDescription
+option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='condition', doc='No change', multi=False, default='tous', values=('tous', 'authentifié', 'aucun'))
+option_4 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
+option_5 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='mode_conteneur_actif2', doc='No change', multi=False, default='non', values=('oui', 'non'))
+option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4, option_5])
+option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
+option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
diff --git a/tests/dictionaries/10load_leadership/makedict/base.json b/tests/dictionaries/10load_leadership/makedict/base.json
index a84a00cf..9e804f6a 100644
--- a/tests/dictionaries/10load_leadership/makedict/base.json
+++ b/tests/dictionaries/10load_leadership/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": "non", "rougail.general1.leader.leader": [], "rougail.general1.leader.follower1": [], "rougail.general1.leader.follower2": []}
+{"rougail.general.mode_conteneur_actif": "non", "rougail.general1.leader.leader": []}
diff --git a/tests/dictionaries/10load_leadership_default_multi/makedict/base.json b/tests/dictionaries/10load_leadership_default_multi/makedict/base.json
index bab2c504..3a48366f 100644
--- a/tests/dictionaries/10load_leadership_default_multi/makedict/base.json
+++ b/tests/dictionaries/10load_leadership_default_multi/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": ["non"], "rougail.general.leader.leader": [], "rougail.general.leader.follower1": [], "rougail.general.leader.follower2": []}
+{"rougail.general.mode_conteneur_actif": ["non"], "rougail.general.leader.leader": []}
diff --git a/tests/dictionaries/10load_leadership_default_submulti/makedict/base.json b/tests/dictionaries/10load_leadership_default_submulti/makedict/base.json
index 63ea34ae..a4b5c0a4 100644
--- a/tests/dictionaries/10load_leadership_default_submulti/makedict/base.json
+++ b/tests/dictionaries/10load_leadership_default_submulti/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": ["non"], "rougail.general.leader.leader": ["leader"], "rougail.general.leader.follower1": [["value"]], "rougail.general.leader.follower2": [["value1", "value2"]]}
+{"rougail.general.mode_conteneur_actif": ["non"], "rougail.general.leader.leader": [{"rougail.general.leader.leader": "leader", "rougail.general.leader.follower1": ["value"], "rougail.general.leader.follower2": ["value1", "value2"]}]}
diff --git a/tests/dictionaries/10load_leadership_defaultmulti_leader/makedict/base.json b/tests/dictionaries/10load_leadership_defaultmulti_leader/makedict/base.json
index ef51ba28..64540f5e 100644
--- a/tests/dictionaries/10load_leadership_defaultmulti_leader/makedict/base.json
+++ b/tests/dictionaries/10load_leadership_defaultmulti_leader/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": ["non"], "rougail.general.leader.leader": ["value"], "rougail.general.leader.follower1": [null], "rougail.general.leader.follower2": [null]}
+{"rougail.general.mode_conteneur_actif": ["non"], "rougail.general.leader.leader": [{"rougail.general.leader.leader": "value", "rougail.general.leader.follower1": null, "rougail.general.leader.follower2": null}]}
diff --git a/tests/dictionaries/10load_leadership_description/makedict/base.json b/tests/dictionaries/10load_leadership_description/makedict/base.json
index a84a00cf..9e804f6a 100644
--- a/tests/dictionaries/10load_leadership_description/makedict/base.json
+++ b/tests/dictionaries/10load_leadership_description/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": "non", "rougail.general1.leader.leader": [], "rougail.general1.leader.follower1": [], "rougail.general1.leader.follower2": []}
+{"rougail.general.mode_conteneur_actif": "non", "rougail.general1.leader.leader": []}
diff --git a/tests/dictionaries/10load_leadership_name/makedict/base.json b/tests/dictionaries/10load_leadership_name/makedict/base.json
index e02048af..9e804f6a 100644
--- a/tests/dictionaries/10load_leadership_name/makedict/base.json
+++ b/tests/dictionaries/10load_leadership_name/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": "non", "rougail.general1.other_name.leader": [], "rougail.general1.other_name.follower1": [], "rougail.general1.other_name.follower2": []}
+{"rougail.general.mode_conteneur_actif": "non", "rougail.general1.leader.leader": []}
diff --git a/tests/dictionaries/10load_leadership_normalize_family/makedict/base.json b/tests/dictionaries/10load_leadership_normalize_family/makedict/base.json
index c2596da8..9cdf5c3e 100644
--- a/tests/dictionaries/10load_leadership_normalize_family/makedict/base.json
+++ b/tests/dictionaries/10load_leadership_normalize_family/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": "non", "rougail.general_1.leader.leader": [], "rougail.general_1.leader.follower1": [], "rougail.general_1.leader.follower2": []}
+{"rougail.general.mode_conteneur_actif": "non", "rougail.general_1.leader.leader": []}
diff --git a/tests/dictionaries/10load_leadership_submulti/makedict/base.json b/tests/dictionaries/10load_leadership_submulti/makedict/base.json
index a84a00cf..9e804f6a 100644
--- a/tests/dictionaries/10load_leadership_submulti/makedict/base.json
+++ b/tests/dictionaries/10load_leadership_submulti/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": "non", "rougail.general1.leader.leader": [], "rougail.general1.leader.follower1": [], "rougail.general1.leader.follower2": []}
+{"rougail.general.mode_conteneur_actif": "non", "rougail.general1.leader.leader": []}
diff --git a/tests/dictionaries/10load_mandatoryifnotin_noexist/00-base.xml b/tests/dictionaries/10load_mandatoryifnotin_noexist/00-base.xml
new file mode 100644
index 00000000..30f24f77
--- /dev/null
+++ b/tests/dictionaries/10load_mandatoryifnotin_noexist/00-base.xml
@@ -0,0 +1,36 @@
+
+
+
+
+
+
+
+ tous
+
+
+ non
+
+
+ non
+
+
+
+
+
+
+
+ tous
+ authentifié
+ aucun
+
+
+ oui
+ non
+ mode_conteneur_actif
+ mode_conteneur_actif2
+
+
+
+
+
diff --git a/tests/dictionaries/10load_mandatoryifnotin_noexist/__init__.py b/tests/dictionaries/10load_mandatoryifnotin_noexist/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/10load_mandatoryifnotin_noexist/makedict/base.json b/tests/dictionaries/10load_mandatoryifnotin_noexist/makedict/base.json
new file mode 100644
index 00000000..3e41cfc3
--- /dev/null
+++ b/tests/dictionaries/10load_mandatoryifnotin_noexist/makedict/base.json
@@ -0,0 +1 @@
+{"rougail.general.condition": "tous", "rougail.general.mode_conteneur_actif": "non", "rougail.general.mode_conteneur_actif2": "non"}
diff --git a/tests/dictionaries/10load_mandatoryifnotin_noexist/tiramisu/__init__.py b/tests/dictionaries/10load_mandatoryifnotin_noexist/tiramisu/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/10load_mandatoryifnotin_noexist/tiramisu/base.py b/tests/dictionaries/10load_mandatoryifnotin_noexist/tiramisu/base.py
new file mode 100644
index 00000000..099f9f5b
--- /dev/null
+++ b/tests/dictionaries/10load_mandatoryifnotin_noexist/tiramisu/base.py
@@ -0,0 +1,16 @@
+from importlib.machinery import SourceFileLoader
+func = SourceFileLoader('func', 'tests/dictionaries/../eosfunc/test.py').load_module()
+for key, value in dict(locals()).items():
+ if key != ['SourceFileLoader', 'func']:
+ setattr(func, key, value)
+try:
+ from tiramisu3 import *
+except:
+ from tiramisu import *
+from rougail.tiramisu import ConvertDynOptionDescription
+option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='condition', doc='No change', multi=False, default='tous', values=('tous', 'authentifié', 'aucun'))
+option_4 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
+option_5 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='mode_conteneur_actif2', doc='No change', multi=False, default='non', values=('oui', 'non'))
+option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4, option_5])
+option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
+option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
diff --git a/tests/dictionaries/10valid_enum_leader/makedict/base.json b/tests/dictionaries/10valid_enum_leader/makedict/base.json
index 3ff8a0ae..107d7b1c 100644
--- a/tests/dictionaries/10valid_enum_leader/makedict/base.json
+++ b/tests/dictionaries/10valid_enum_leader/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": "non", "rougail.general.leader.leader": [], "rougail.general.leader.follower1": [], "rougail.general.leader.follower2": []}
+{"rougail.general.mode_conteneur_actif": "non", "rougail.general.leader.leader": []}
diff --git a/tests/dictionaries/10valid_enum_param_empty/00-base.xml b/tests/dictionaries/10valid_enum_param_empty/00-base.xml
new file mode 100644
index 00000000..a73090a6
--- /dev/null
+++ b/tests/dictionaries/10valid_enum_param_empty/00-base.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+ non
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/dictionaries/10valid_enum_param_empty/__init__.py b/tests/dictionaries/10valid_enum_param_empty/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/10valid_enum_param_empty/makedict/base.json b/tests/dictionaries/10valid_enum_param_empty/makedict/base.json
new file mode 100644
index 00000000..9f9d92af
--- /dev/null
+++ b/tests/dictionaries/10valid_enum_param_empty/makedict/base.json
@@ -0,0 +1 @@
+{"rougail.general.mode_conteneur_actif": "non", "rougail.enumfam.enumvar": null}
diff --git a/tests/dictionaries/10valid_enum_param_empty/tiramisu/base.py b/tests/dictionaries/10valid_enum_param_empty/tiramisu/base.py
new file mode 100644
index 00000000..eb614366
--- /dev/null
+++ b/tests/dictionaries/10valid_enum_param_empty/tiramisu/base.py
@@ -0,0 +1,17 @@
+from importlib.machinery import SourceFileLoader
+func = SourceFileLoader('func', 'tests/dictionaries/../eosfunc/test.py').load_module()
+for key, value in dict(locals()).items():
+ if key != ['SourceFileLoader', 'func']:
+ setattr(func, key, value)
+try:
+ from tiramisu3 import *
+except:
+ from tiramisu import *
+from rougail.tiramisu import ConvertDynOptionDescription
+option_3 = ChoiceOption(properties=frozenset({'expert', 'mandatory'}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
+option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'expert'}), children=[option_3])
+option_5 = ChoiceOption(properties=frozenset({'expert', 'mandatory'}), name='enumvar', doc='multi', multi=False, values=(None,))
+option_5.impl_set_information("help", "bla bla bla")
+option_4 = OptionDescription(name='enumfam', doc='enumfam', properties=frozenset({'expert'}), children=[option_5])
+option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2, option_4])
+option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
diff --git a/tests/dictionaries/10valid_enum_param_empty2/00-base.xml b/tests/dictionaries/10valid_enum_param_empty2/00-base.xml
new file mode 100644
index 00000000..e2dcfadb
--- /dev/null
+++ b/tests/dictionaries/10valid_enum_param_empty2/00-base.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+ non
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/dictionaries/10valid_enum_param_empty2/__init__.py b/tests/dictionaries/10valid_enum_param_empty2/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/10valid_enum_param_empty2/makedict/base.json b/tests/dictionaries/10valid_enum_param_empty2/makedict/base.json
new file mode 100644
index 00000000..9f9d92af
--- /dev/null
+++ b/tests/dictionaries/10valid_enum_param_empty2/makedict/base.json
@@ -0,0 +1 @@
+{"rougail.general.mode_conteneur_actif": "non", "rougail.enumfam.enumvar": null}
diff --git a/tests/dictionaries/10valid_enum_param_empty2/tiramisu/base.py b/tests/dictionaries/10valid_enum_param_empty2/tiramisu/base.py
new file mode 100644
index 00000000..eb614366
--- /dev/null
+++ b/tests/dictionaries/10valid_enum_param_empty2/tiramisu/base.py
@@ -0,0 +1,17 @@
+from importlib.machinery import SourceFileLoader
+func = SourceFileLoader('func', 'tests/dictionaries/../eosfunc/test.py').load_module()
+for key, value in dict(locals()).items():
+ if key != ['SourceFileLoader', 'func']:
+ setattr(func, key, value)
+try:
+ from tiramisu3 import *
+except:
+ from tiramisu import *
+from rougail.tiramisu import ConvertDynOptionDescription
+option_3 = ChoiceOption(properties=frozenset({'expert', 'mandatory'}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
+option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'expert'}), children=[option_3])
+option_5 = ChoiceOption(properties=frozenset({'expert', 'mandatory'}), name='enumvar', doc='multi', multi=False, values=(None,))
+option_5.impl_set_information("help", "bla bla bla")
+option_4 = OptionDescription(name='enumfam', doc='enumfam', properties=frozenset({'expert'}), children=[option_5])
+option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2, option_4])
+option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
diff --git a/tests/dictionaries/20family_dynamic_calc2/00-base.xml b/tests/dictionaries/20family_dynamic_calc2/00-base.xml
new file mode 100644
index 00000000..9020ece0
--- /dev/null
+++ b/tests/dictionaries/20family_dynamic_calc2/00-base.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+ val1
+ val2
+
+
+
+
+ val
+
+
+
+
+
+
+
+
+ non
+ dyn
+
+
+
diff --git a/tests/dictionaries/20family_dynamic_calc2/__init__.py b/tests/dictionaries/20family_dynamic_calc2/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/20family_dynamic_calc2/makedict/base.json b/tests/dictionaries/20family_dynamic_calc2/makedict/base.json
new file mode 100644
index 00000000..82b6fff8
--- /dev/null
+++ b/tests/dictionaries/20family_dynamic_calc2/makedict/base.json
@@ -0,0 +1 @@
+{"rougail.general.varname": ["val1", "val2"], "rougail.dynval1.vardynval1": "val", "rougail.dynval2.vardynval2": "val", "rougail.new.newvar": null}
diff --git a/tests/dictionaries/20family_dynamic_calc2/tiramisu/__init__.py b/tests/dictionaries/20family_dynamic_calc2/tiramisu/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/20family_dynamic_calc2/tiramisu/base.py b/tests/dictionaries/20family_dynamic_calc2/tiramisu/base.py
new file mode 100644
index 00000000..b834b573
--- /dev/null
+++ b/tests/dictionaries/20family_dynamic_calc2/tiramisu/base.py
@@ -0,0 +1,18 @@
+from importlib.machinery import SourceFileLoader
+func = SourceFileLoader('func', 'tests/dictionaries/../eosfunc/test.py').load_module()
+for key, value in dict(locals()).items():
+ if key != ['SourceFileLoader', 'func']:
+ setattr(func, key, value)
+try:
+ from tiramisu3 import *
+except:
+ from tiramisu import *
+from rougail.tiramisu import ConvertDynOptionDescription
+option_3 = StrOption(properties=frozenset({'mandatory', 'normal'}), name='varname', doc='No change', multi=True, default=['val1', 'val2'], default_multi='val2')
+option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3])
+option_7 = StrOption(properties=frozenset({'normal'}), name='newvar', doc='No change', multi=False)
+option_5 = StrOption(properties=frozenset({'mandatory', 'normal', Calculation(calc_value, Params(ParamValue('frozen'), kwargs={'condition': ParamOption(option_7, todict=True), 'expected': ParamValue('non')})), Calculation(calc_value, Params(ParamValue('force_default_on_freeze'), kwargs={'condition': ParamOption(option_7, todict=True), 'expected': ParamValue('non')}))}), name='vardyn', doc='No change', multi=False, default='val')
+option_4 = ConvertDynOptionDescription(name='dyn', doc='dyn', suffixes=Calculation(func.calc_value, Params((ParamOption(option_3)))), properties=frozenset({'normal', Calculation(calc_value, Params(ParamValue('hidden'), kwargs={'condition': ParamOption(option_7, todict=True), 'expected': ParamValue('non')}))}), children=[option_5])
+option_6 = OptionDescription(name='new', doc='new', properties=frozenset({'normal'}), children=[option_7])
+option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2, option_4, option_6])
+option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
diff --git a/tests/dictionaries/20family_modeleadership/makedict/base.json b/tests/dictionaries/20family_modeleadership/makedict/base.json
index 3ff8a0ae..107d7b1c 100644
--- a/tests/dictionaries/20family_modeleadership/makedict/base.json
+++ b/tests/dictionaries/20family_modeleadership/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": "non", "rougail.general.leader.leader": [], "rougail.general.leader.follower1": [], "rougail.general.leader.follower2": []}
+{"rougail.general.mode_conteneur_actif": "non", "rougail.general.leader.leader": []}
diff --git a/tests/dictionaries/40condition_optional_empty/00-base.xml b/tests/dictionaries/40condition_optional_empty/00-base.xml
new file mode 100644
index 00000000..85a25ecc
--- /dev/null
+++ b/tests/dictionaries/40condition_optional_empty/00-base.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+ non
+
+
+ non
+
+
+ non
+
+
+
+
+
+
+ oui
+ mode_conteneur_actif2
+
+
+
+
diff --git a/tests/dictionaries/40condition_optional_empty/__init__.py b/tests/dictionaries/40condition_optional_empty/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/40condition_optional_empty/makedict/base.json b/tests/dictionaries/40condition_optional_empty/makedict/base.json
new file mode 100644
index 00000000..6008a9ce
--- /dev/null
+++ b/tests/dictionaries/40condition_optional_empty/makedict/base.json
@@ -0,0 +1 @@
+{"rougail.general.mode_conteneur_actif": "non", "rougail.general.condition": "non", "rougail.general.mode_conteneur_actif1": "non"}
diff --git a/tests/dictionaries/40condition_optional_empty/tiramisu/__init__.py b/tests/dictionaries/40condition_optional_empty/tiramisu/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/40condition_optional_empty/tiramisu/base.py b/tests/dictionaries/40condition_optional_empty/tiramisu/base.py
new file mode 100644
index 00000000..5f746d25
--- /dev/null
+++ b/tests/dictionaries/40condition_optional_empty/tiramisu/base.py
@@ -0,0 +1,16 @@
+from importlib.machinery import SourceFileLoader
+func = SourceFileLoader('func', 'tests/dictionaries/../eosfunc/test.py').load_module()
+for key, value in dict(locals()).items():
+ if key != ['SourceFileLoader', 'func']:
+ setattr(func, key, value)
+try:
+ from tiramisu3 import *
+except:
+ from tiramisu import *
+from rougail.tiramisu import ConvertDynOptionDescription
+option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
+option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='condition', doc='No change', multi=False, default='non', values=('oui', 'non'))
+option_5 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif1', doc='No change', multi=False, default='non', values=('oui', 'non'))
+option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4, option_5])
+option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
+option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
diff --git a/tests/dictionaries/40hidden_if_in_group_fallback/makedict/base.json b/tests/dictionaries/40hidden_if_in_group_fallback/makedict/base.json
index 8e8eadbe..944631ab 100644
--- a/tests/dictionaries/40hidden_if_in_group_fallback/makedict/base.json
+++ b/tests/dictionaries/40hidden_if_in_group_fallback/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": "non", "rougail.general.mode_conteneur_actif1.mode_conteneur_actif1": ["non"], "rougail.general.mode_conteneur_actif1.mode_conteneur_actif2": ["non"]}
+{"rougail.general.mode_conteneur_actif": "non", "rougail.general.mode_conteneur_actif1.mode_conteneur_actif1": [{"rougail.general.mode_conteneur_actif1.mode_conteneur_actif1": "non", "rougail.general.mode_conteneur_actif1.mode_conteneur_actif2": "non"}]}
diff --git a/tests/dictionaries/40ifin_leadership/makedict/base.json b/tests/dictionaries/40ifin_leadership/makedict/base.json
index ef2026a8..22441eab 100644
--- a/tests/dictionaries/40ifin_leadership/makedict/base.json
+++ b/tests/dictionaries/40ifin_leadership/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": "non", "rougail.general.condition": "oui", "rougail.general.leader.leader": [], "rougail.general.leader.follower2": []}
+{"rougail.general.mode_conteneur_actif": "non", "rougail.general.condition": "oui", "rougail.general.leader.leader": []}
diff --git a/tests/dictionaries/40ifin_leadershipauto/00-base.xml b/tests/dictionaries/40ifin_leadershipauto/00-base.xml
index d4556f38..dff4a4b1 100644
--- a/tests/dictionaries/40ifin_leadershipauto/00-base.xml
+++ b/tests/dictionaries/40ifin_leadershipauto/00-base.xml
@@ -1,17 +1,23 @@
+
+
+
+
+
non
-
+
+ a
+
-
follower1
diff --git a/tests/dictionaries/40ifin_leadershipauto/makedict/base.json b/tests/dictionaries/40ifin_leadershipauto/makedict/base.json
index ef2026a8..9c202b00 100644
--- a/tests/dictionaries/40ifin_leadershipauto/makedict/base.json
+++ b/tests/dictionaries/40ifin_leadershipauto/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": "non", "rougail.general.condition": "oui", "rougail.general.leader.leader": [], "rougail.general.leader.follower2": []}
+{"rougail.general.mode_conteneur_actif": "non", "rougail.general.condition": "oui", "rougail.general.leader.leader": [{"rougail.general.leader.leader": "a", "rougail.general.leader.follower2": null}], "services.test.files.mailname.group": "root", "services.test.files.mailname.mode": "0644", "services.test.files.mailname.name": "/etc/mailname", "services.test.files.mailname.owner": "root", "services.test.files.mailname.source": "mailname", "services.test.files.mailname.templating": true, "services.test.files.mailname.activate": true}
diff --git a/tests/dictionaries/40ifin_leadershipauto/result/etc/mailname b/tests/dictionaries/40ifin_leadershipauto/result/etc/mailname
new file mode 100644
index 00000000..155aa30c
--- /dev/null
+++ b/tests/dictionaries/40ifin_leadershipauto/result/etc/mailname
@@ -0,0 +1,2 @@
+leader: a
+follower2:
diff --git a/tests/dictionaries/40ifin_leadershipauto/tiramisu/base.py b/tests/dictionaries/40ifin_leadershipauto/tiramisu/base.py
index 7daf47d8..28d08a4b 100644
--- a/tests/dictionaries/40ifin_leadershipauto/tiramisu/base.py
+++ b/tests/dictionaries/40ifin_leadershipauto/tiramisu/base.py
@@ -10,10 +10,22 @@ except:
from rougail.tiramisu import ConvertDynOptionDescription
option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='condition', doc='condition', multi=False, default='oui', values=('oui', 'non'))
-option_6 = StrOption(name='leader', doc='leader', multi=True)
+option_6 = StrOption(properties=frozenset({'mandatory'}), name='leader', doc='leader', multi=True, default=['a'])
option_7 = StrOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'normal', Calculation(calc_value, Params(ParamValue('disabled'), kwargs={'condition': ParamOption(option_4, todict=True), 'expected': ParamValue('oui')}))}), name='follower1', doc='follower1', multi=True, default=Calculation(func.calc_val, Params((), kwargs={'valeur': ParamValue("valfill")})))
option_8 = StrOption(properties=frozenset({'normal'}), name='follower2', doc='follower2', multi=True)
option_5 = Leadership(name='leader', doc='leader', properties=frozenset({'normal'}), children=[option_6, option_7, option_8])
option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4, option_5])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
-option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1])
+option_13 = StrOption(name='group', doc='group', multi=False, default='root')
+option_14 = StrOption(name='mode', doc='mode', multi=False, default='0644')
+option_15 = StrOption(name='name', doc='name', multi=False, default='/etc/mailname')
+option_16 = StrOption(name='owner', doc='owner', multi=False, default='root')
+option_17 = StrOption(name='source', doc='source', multi=False, default='mailname')
+option_18 = BoolOption(name='templating', doc='templating', multi=False, default=True)
+option_19 = BoolOption(name='activate', doc='activate', multi=False, default=True)
+option_12 = OptionDescription(name='mailname', doc='mailname', children=[option_13, option_14, option_15, option_16, option_17, option_18, option_19])
+option_11 = OptionDescription(name='files', doc='files', children=[option_12])
+option_10 = OptionDescription(name='test', doc='test', children=[option_11])
+option_10.impl_set_information("manage", True)
+option_9 = OptionDescription(name='services', doc='services', properties=frozenset({'hidden'}), children=[option_10])
+option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1, option_9])
diff --git a/tests/dictionaries/40ifin_leadershipauto/tmpl/mailname b/tests/dictionaries/40ifin_leadershipauto/tmpl/mailname
new file mode 100644
index 00000000..43dbe7d1
--- /dev/null
+++ b/tests/dictionaries/40ifin_leadershipauto/tmpl/mailname
@@ -0,0 +1,9 @@
+%for %%lead in %%leader
+leader: %%lead
+%if %%hasattr(%%lead, 'follower1')
+follower1: %%lead.follower1
+%end if
+%if %%hasattr(%%lead, 'follower2')
+follower2: %%lead.follower2
+%end if
+%end for
diff --git a/tests/dictionaries/40ifin_leadershipauto_follower/00-base.xml b/tests/dictionaries/40ifin_leadershipauto_follower/00-base.xml
new file mode 100644
index 00000000..032b0814
--- /dev/null
+++ b/tests/dictionaries/40ifin_leadershipauto_follower/00-base.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
+
+ non
+
+
+
+ a
+ b
+
+
+
+
+
+
+
+ follower1
+ follower2
+
+
+ valfill
+
+
+ a
+ follower1
+
+
+
diff --git a/tests/dictionaries/40ifin_leadershipauto_follower/__init__.py b/tests/dictionaries/40ifin_leadershipauto_follower/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/40ifin_leadershipauto_follower/makedict/base.json b/tests/dictionaries/40ifin_leadershipauto_follower/makedict/base.json
new file mode 100644
index 00000000..9aa54e37
--- /dev/null
+++ b/tests/dictionaries/40ifin_leadershipauto_follower/makedict/base.json
@@ -0,0 +1 @@
+{"rougail.general.mode_conteneur_actif": "non", "rougail.general.condition": "oui", "rougail.general.leader.leader": [{"rougail.general.leader.leader": "a", "rougail.general.leader.follower2": null}, {"rougail.general.leader.leader": "b", "rougail.general.leader.follower1": null, "rougail.general.leader.follower2": null}], "services.test.files.mailname.group": "root", "services.test.files.mailname.mode": "0644", "services.test.files.mailname.name": "/etc/mailname", "services.test.files.mailname.owner": "root", "services.test.files.mailname.source": "mailname", "services.test.files.mailname.templating": true, "services.test.files.mailname.activate": true}
diff --git a/tests/dictionaries/40ifin_leadershipauto_follower/result/etc/mailname b/tests/dictionaries/40ifin_leadershipauto_follower/result/etc/mailname
new file mode 100644
index 00000000..b7cbd32c
--- /dev/null
+++ b/tests/dictionaries/40ifin_leadershipauto_follower/result/etc/mailname
@@ -0,0 +1,5 @@
+leader: a
+follower2:
+leader: b
+follower1:
+follower2:
diff --git a/tests/dictionaries/40ifin_leadershipauto_follower/tiramisu/base.py b/tests/dictionaries/40ifin_leadershipauto_follower/tiramisu/base.py
new file mode 100644
index 00000000..4dac5790
--- /dev/null
+++ b/tests/dictionaries/40ifin_leadershipauto_follower/tiramisu/base.py
@@ -0,0 +1,31 @@
+from importlib.machinery import SourceFileLoader
+func = SourceFileLoader('func', 'tests/dictionaries/../eosfunc/test.py').load_module()
+for key, value in dict(locals()).items():
+ if key != ['SourceFileLoader', 'func']:
+ setattr(func, key, value)
+try:
+ from tiramisu3 import *
+except:
+ from tiramisu import *
+from rougail.tiramisu import ConvertDynOptionDescription
+option_3 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='non', values=('oui', 'non'))
+option_4 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='condition', doc='condition', multi=False, default='oui', values=('oui', 'non'))
+option_6 = StrOption(properties=frozenset({'mandatory'}), name='leader', doc='leader', multi=True, default=['a', 'b'])
+option_7 = StrOption(properties=frozenset({'normal', Calculation(calc_value, Params(ParamValue('disabled'), kwargs={'condition': ParamOption(option_6, todict=True), 'expected': ParamValue('a')}))}), name='follower1', doc='follower1', multi=True, default=Calculation(func.calc_val, Params((), kwargs={'valeur': ParamValue("valfill")})))
+option_8 = StrOption(properties=frozenset({'normal'}), name='follower2', doc='follower2', multi=True)
+option_5 = Leadership(name='leader', doc='leader', properties=frozenset({'normal'}), children=[option_6, option_7, option_8])
+option_2 = OptionDescription(name='general', doc='general', properties=frozenset({'normal'}), children=[option_3, option_4, option_5])
+option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
+option_13 = StrOption(name='group', doc='group', multi=False, default='root')
+option_14 = StrOption(name='mode', doc='mode', multi=False, default='0644')
+option_15 = StrOption(name='name', doc='name', multi=False, default='/etc/mailname')
+option_16 = StrOption(name='owner', doc='owner', multi=False, default='root')
+option_17 = StrOption(name='source', doc='source', multi=False, default='mailname')
+option_18 = BoolOption(name='templating', doc='templating', multi=False, default=True)
+option_19 = BoolOption(name='activate', doc='activate', multi=False, default=True)
+option_12 = OptionDescription(name='mailname', doc='mailname', children=[option_13, option_14, option_15, option_16, option_17, option_18, option_19])
+option_11 = OptionDescription(name='files', doc='files', children=[option_12])
+option_10 = OptionDescription(name='test', doc='test', children=[option_11])
+option_10.impl_set_information("manage", True)
+option_9 = OptionDescription(name='services', doc='services', properties=frozenset({'hidden'}), children=[option_10])
+option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1, option_9])
diff --git a/tests/dictionaries/40ifin_leadershipauto_follower/tmpl/mailname b/tests/dictionaries/40ifin_leadershipauto_follower/tmpl/mailname
new file mode 100644
index 00000000..43dbe7d1
--- /dev/null
+++ b/tests/dictionaries/40ifin_leadershipauto_follower/tmpl/mailname
@@ -0,0 +1,9 @@
+%for %%lead in %%leader
+leader: %%lead
+%if %%hasattr(%%lead, 'follower1')
+follower1: %%lead.follower1
+%end if
+%if %%hasattr(%%lead, 'follower2')
+follower2: %%lead.follower2
+%end if
+%end for
diff --git a/tests/dictionaries/60extra_group/makedict/base.json b/tests/dictionaries/60extra_group/makedict/base.json
index 0e2661fc..c5fedd54 100644
--- a/tests/dictionaries/60extra_group/makedict/base.json
+++ b/tests/dictionaries/60extra_group/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": "non", "rougail.general.activer_ejabberd": "non", "extra.ejabberd.description.description": ["test"], "extra.ejabberd.description.mode": ["pre"], "services.test.files.mailname.group": "root", "services.test.files.mailname.mode": "0644", "services.test.files.mailname.name": "/etc/mailname", "services.test.files.mailname.owner": "root", "services.test.files.mailname.source": "mailname", "services.test.files.mailname.templating": true, "services.test.files.mailname.activate": true}
+{"rougail.general.mode_conteneur_actif": "non", "rougail.general.activer_ejabberd": "non", "extra.ejabberd.description.description": [{"extra.ejabberd.description.description": "test", "extra.ejabberd.description.mode": "pre"}], "services.test.files.mailname.group": "root", "services.test.files.mailname.mode": "0644", "services.test.files.mailname.name": "/etc/mailname", "services.test.files.mailname.owner": "root", "services.test.files.mailname.source": "mailname", "services.test.files.mailname.templating": true, "services.test.files.mailname.activate": true}
diff --git a/tests/dictionaries/60extra_group/result/etc/mailname b/tests/dictionaries/60extra_group/result/etc/mailname
index ecca61d9..dc34cc5b 100644
--- a/tests/dictionaries/60extra_group/result/etc/mailname
+++ b/tests/dictionaries/60extra_group/result/etc/mailname
@@ -1 +1,11 @@
-pre
+contain test
+1
+leader: test
+follower: pre
+supeq
+sup
+diff
+testpre
+pretest
+leader2: test
+follower2: pre
diff --git a/tests/dictionaries/60extra_group/tmpl/mailname b/tests/dictionaries/60extra_group/tmpl/mailname
index da3e807a..de1500e6 100644
--- a/tests/dictionaries/60extra_group/tmpl/mailname
+++ b/tests/dictionaries/60extra_group/tmpl/mailname
@@ -1,3 +1,35 @@
+%if 'test' in %%extra.ejabberd.description
+contain test
+%end if
+%%len(%%extra.ejabberd.description)
+%if 'a' in %%extra.ejabberd.description
+contain a
+%end if
%for %%description in %%extra.ejabberd.description
-%%description.mode
+leader: %%description
+follower: %%description.mode
+%if %%description <= %%description.mode
+infeq
+%end if
+%if %%description >= %%description.mode
+supeq
+%end if
+%if %%description < %%description.mode
+inf
+%end if
+%if %%description > %%description.mode
+sup
+%end if
+%if %%description == %%description.mode
+eq
+%end if
+%if %%description != %%description.mode
+diff
+%end if
+%set %%var = %%description + %%description.mode
+%%var
+%set %%var = %%description.mode + %%description
+%%var
%end for
+leader2: %%extra.ejabberd.description[0]
+follower2: %%extra.ejabberd.description[0].mode
diff --git a/tests/dictionaries/61extra_dyn/00-base.xml b/tests/dictionaries/61extra_dyn/00-base.xml
new file mode 100644
index 00000000..c243504c
--- /dev/null
+++ b/tests/dictionaries/61extra_dyn/00-base.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+ a
+
+
+
+
+
diff --git a/tests/dictionaries/61extra_dyn/__init__.py b/tests/dictionaries/61extra_dyn/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/61extra_dyn/extra_dirs/extra/00-base.xml b/tests/dictionaries/61extra_dyn/extra_dirs/extra/00-base.xml
new file mode 100644
index 00000000..b8b0ca1f
--- /dev/null
+++ b/tests/dictionaries/61extra_dyn/extra_dirs/extra/00-base.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/tests/dictionaries/61extra_dyn/makedict/base.json b/tests/dictionaries/61extra_dyn/makedict/base.json
new file mode 100644
index 00000000..4df71f24
--- /dev/null
+++ b/tests/dictionaries/61extra_dyn/makedict/base.json
@@ -0,0 +1 @@
+{"rougail.general.varname": ["a"], "extra.ejabberda.modea": null}
diff --git a/tests/dictionaries/61extra_dyn/tiramisu/base.py b/tests/dictionaries/61extra_dyn/tiramisu/base.py
new file mode 100644
index 00000000..899034f2
--- /dev/null
+++ b/tests/dictionaries/61extra_dyn/tiramisu/base.py
@@ -0,0 +1,17 @@
+from importlib.machinery import SourceFileLoader
+func = SourceFileLoader('func', 'tests/dictionaries/../eosfunc/test.py').load_module()
+for key, value in dict(locals()).items():
+ if key != ['SourceFileLoader', 'func']:
+ setattr(func, key, value)
+try:
+ from tiramisu3 import *
+except:
+ from tiramisu import *
+from rougail.tiramisu import ConvertDynOptionDescription
+option_3 = StrOption(properties=frozenset({'mandatory', 'normal'}), name='varname', doc='No change', multi=True, default=['a'], default_multi='a')
+option_2 = OptionDescription(name='general', doc='général', properties=frozenset({'normal'}), children=[option_3])
+option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
+option_6 = StrOption(properties=frozenset({'normal'}), name='mode', doc='mode', multi=False)
+option_5 = ConvertDynOptionDescription(name='ejabberd', doc='ejabberd', suffixes=Calculation(func.calc_value, Params((ParamOption(option_3)))), properties=frozenset({'normal'}), children=[option_6])
+option_4 = OptionDescription(name='extra', doc='extra', children=[option_5])
+option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1, option_4])
diff --git a/tests/dictionaries/61extra_dyn_extra/00-base.xml b/tests/dictionaries/61extra_dyn_extra/00-base.xml
new file mode 100644
index 00000000..c243504c
--- /dev/null
+++ b/tests/dictionaries/61extra_dyn_extra/00-base.xml
@@ -0,0 +1,12 @@
+
+
+
+
+
+ a
+
+
+
+
+
diff --git a/tests/dictionaries/61extra_dyn_extra/__init__.py b/tests/dictionaries/61extra_dyn_extra/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/61extra_dyn_extra/extra_dirs/extra/00-base.xml b/tests/dictionaries/61extra_dyn_extra/extra_dirs/extra/00-base.xml
new file mode 100644
index 00000000..b799098d
--- /dev/null
+++ b/tests/dictionaries/61extra_dyn_extra/extra_dirs/extra/00-base.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+ a
+
+
+
+
+
+
+
diff --git a/tests/dictionaries/61extra_dyn_extra/makedict/base.json b/tests/dictionaries/61extra_dyn_extra/makedict/base.json
new file mode 100644
index 00000000..27255994
--- /dev/null
+++ b/tests/dictionaries/61extra_dyn_extra/makedict/base.json
@@ -0,0 +1 @@
+{"rougail.general.varname": ["a"], "extra.general.varname": ["a"], "extra.ejabberda.modea": null}
diff --git a/tests/dictionaries/61extra_dyn_extra/tiramisu/base.py b/tests/dictionaries/61extra_dyn_extra/tiramisu/base.py
new file mode 100644
index 00000000..67aab539
--- /dev/null
+++ b/tests/dictionaries/61extra_dyn_extra/tiramisu/base.py
@@ -0,0 +1,19 @@
+from importlib.machinery import SourceFileLoader
+func = SourceFileLoader('func', 'tests/dictionaries/../eosfunc/test.py').load_module()
+for key, value in dict(locals()).items():
+ if key != ['SourceFileLoader', 'func']:
+ setattr(func, key, value)
+try:
+ from tiramisu3 import *
+except:
+ from tiramisu import *
+from rougail.tiramisu import ConvertDynOptionDescription
+option_3 = StrOption(properties=frozenset({'mandatory', 'normal'}), name='varname', doc='No change', multi=True, default=['a'], default_multi='a')
+option_2 = OptionDescription(name='general', doc='général', properties=frozenset({'normal'}), children=[option_3])
+option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
+option_6 = StrOption(properties=frozenset({'mandatory', 'normal'}), name='varname', doc='No change', multi=True, default=['a'], default_multi='a')
+option_5 = OptionDescription(name='general', doc='général', properties=frozenset({'normal'}), children=[option_6])
+option_8 = StrOption(properties=frozenset({'normal'}), name='mode', doc='mode', multi=False)
+option_7 = ConvertDynOptionDescription(name='ejabberd', doc='ejabberd', suffixes=Calculation(func.calc_value, Params((ParamOption(option_6)))), properties=frozenset({'normal'}), children=[option_8])
+option_4 = OptionDescription(name='extra', doc='extra', children=[option_5, option_7])
+option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1, option_4])
diff --git a/tests/dictionaries/70container_files/tmpl/mailname b/tests/dictionaries/70container_files/tmpl/mailname
index ee573d64..3ae41fab 100644
--- a/tests/dictionaries/70container_files/tmpl/mailname
+++ b/tests/dictionaries/70container_files/tmpl/mailname
@@ -1,6 +1,6 @@
-%if %%is_defined('mode_conteneur_actif')
+%if %%varExists('mode_conteneur_actif')
%%mode_conteneur_actif
%end if
-%if %%is_defined('mode_conteneur_actif3')
+%if %%varExists('mode_conteneur_actif3')
%%mode_conteneur_actif3
%end if
diff --git a/tests/dictionaries/70container_files_symlink_variable/00-base.xml b/tests/dictionaries/70container_files_symlink_variable/00-base.xml
new file mode 100644
index 00000000..186ade03
--- /dev/null
+++ b/tests/dictionaries/70container_files_symlink_variable/00-base.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+ oui
+
+
+ /etc/mailname
+
+
+ mailname
+
+
+
+
+
diff --git a/tests/dictionaries/70container_files_symlink_variable/__init__.py b/tests/dictionaries/70container_files_symlink_variable/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/70container_files_symlink_variable/makedict/base.json b/tests/dictionaries/70container_files_symlink_variable/makedict/base.json
new file mode 100644
index 00000000..3e00b14c
--- /dev/null
+++ b/tests/dictionaries/70container_files_symlink_variable/makedict/base.json
@@ -0,0 +1 @@
+{"rougail.general.mode_conteneur_actif": "oui", "rougail.general.file_name": "/etc/mailname", "rougail.general.var": "mailname", "services.test.files.mailname.group": "root", "services.test.files.mailname.mode": "0644", "services.test.files.mailname.name": "/etc/mailname", "services.test.files.mailname.owner": "root", "services.test.files.mailname.source": "mailname", "services.test.files.mailname.templating": true, "services.test.files.mailname.variable": "mailname", "services.test.files.mailname.activate": true}
diff --git a/tests/dictionaries/70container_files_symlink_variable/result/etc/mailname b/tests/dictionaries/70container_files_symlink_variable/result/etc/mailname
new file mode 100644
index 00000000..0288f489
--- /dev/null
+++ b/tests/dictionaries/70container_files_symlink_variable/result/etc/mailname
@@ -0,0 +1 @@
+mailname
diff --git a/tests/dictionaries/70container_files_symlink_variable/tiramisu/__init__.py b/tests/dictionaries/70container_files_symlink_variable/tiramisu/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/70container_files_symlink_variable/tiramisu/base.py b/tests/dictionaries/70container_files_symlink_variable/tiramisu/base.py
new file mode 100644
index 00000000..09830090
--- /dev/null
+++ b/tests/dictionaries/70container_files_symlink_variable/tiramisu/base.py
@@ -0,0 +1,29 @@
+from importlib.machinery import SourceFileLoader
+func = SourceFileLoader('func', 'tests/dictionaries/../eosfunc/test.py').load_module()
+for key, value in dict(locals()).items():
+ if key != ['SourceFileLoader', 'func']:
+ setattr(func, key, value)
+try:
+ from tiramisu3 import *
+except:
+ from tiramisu import *
+from rougail.tiramisu import ConvertDynOptionDescription
+option_3 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='mode_conteneur_actif', doc='No change', multi=False, default='oui', values=('oui', 'non'))
+option_4 = StrOption(properties=frozenset({'mandatory', 'normal'}), name='file_name', doc='file_name', multi=False, default='/etc/mailname')
+option_5 = StrOption(properties=frozenset({'mandatory', 'normal'}), name='var', doc='var', multi=False, default='mailname')
+option_2 = OptionDescription(name='general', doc='général', properties=frozenset({'normal'}), children=[option_3, option_4, option_5])
+option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
+option_10 = StrOption(name='group', doc='group', multi=False, default='root')
+option_11 = StrOption(name='mode', doc='mode', multi=False, default='0644')
+option_12 = SymLinkOption(name='name', opt=option_4)
+option_13 = StrOption(name='owner', doc='owner', multi=False, default='root')
+option_14 = StrOption(name='source', doc='source', multi=False, default='mailname')
+option_15 = BoolOption(name='templating', doc='templating', multi=False, default=True)
+option_16 = SymLinkOption(name='variable', opt=option_5)
+option_17 = BoolOption(name='activate', doc='activate', multi=False, default=True)
+option_9 = OptionDescription(name='mailname', doc='mailname', children=[option_10, option_11, option_12, option_13, option_14, option_15, option_16, option_17])
+option_8 = OptionDescription(name='files', doc='files', children=[option_9])
+option_7 = OptionDescription(name='test', doc='test', children=[option_8])
+option_7.impl_set_information("manage", True)
+option_6 = OptionDescription(name='services', doc='services', properties=frozenset({'hidden'}), children=[option_7])
+option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1, option_6])
diff --git a/tests/dictionaries/70container_files_symlink_variable/tmpl/mailname b/tests/dictionaries/70container_files_symlink_variable/tmpl/mailname
new file mode 100644
index 00000000..5ecb01bb
--- /dev/null
+++ b/tests/dictionaries/70container_files_symlink_variable/tmpl/mailname
@@ -0,0 +1 @@
+%%rougail_variable
diff --git a/tests/dictionaries/70container_pathaccess_leadership/makedict/base.json b/tests/dictionaries/70container_pathaccess_leadership/makedict/base.json
index 91903fe8..1938aa84 100644
--- a/tests/dictionaries/70container_pathaccess_leadership/makedict/base.json
+++ b/tests/dictionaries/70container_pathaccess_leadership/makedict/base.json
@@ -1 +1 @@
-{"rougail.general.mode_conteneur_actif": "oui", "rougail.general.nut_monitor_netmask.nut_monitor_netmask": [], "rougail.general.nut_monitor_netmask.nut_monitor_host": [], "services.ntp.ips.nut_monitor_host.interface": "auto", "services.ntp.ips.nut_monitor_host.name": [], "services.ntp.ips.nut_monitor_host.netmask": [], "services.ntp.ips.nut_monitor_host.activate": true}
+{"rougail.general.mode_conteneur_actif": "oui", "rougail.general.nut_monitor_netmask.nut_monitor_netmask": [], "services.ntp.ips.nut_monitor_host.interface": "auto", "services.ntp.ips.nut_monitor_host.name": [], "services.ntp.ips.nut_monitor_host.netmask": [], "services.ntp.ips.nut_monitor_host.activate": true}
diff --git a/tests/dictionaries/80check_without_target/00-base.xml b/tests/dictionaries/80check_without_target/00-base.xml
new file mode 100644
index 00000000..a586fe52
--- /dev/null
+++ b/tests/dictionaries/80check_without_target/00-base.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+ b
+
+
+
+
+
+
+
+ 0
+ 100
+
+
+
+
diff --git a/tests/dictionaries/80check_without_target/__init__.py b/tests/dictionaries/80check_without_target/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80check_without_target/errno_43 b/tests/dictionaries/80check_without_target/errno_43
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80condition_not_exists_error_var/00-base.xml b/tests/dictionaries/80condition_not_exists_error_var/00-base.xml
new file mode 100644
index 00000000..adf99a27
--- /dev/null
+++ b/tests/dictionaries/80condition_not_exists_error_var/00-base.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+ non
+
+
+
+
+
+
+
+ oui
+ notexists
+
+
+
+
diff --git a/tests/dictionaries/80condition_not_exists_error_var/__init__.py b/tests/dictionaries/80condition_not_exists_error_var/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80condition_not_exists_error_var/errno_42 b/tests/dictionaries/80condition_not_exists_error_var/errno_42
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80condition_without_target/00-base.xml b/tests/dictionaries/80condition_without_target/00-base.xml
new file mode 100644
index 00000000..b371fef1
--- /dev/null
+++ b/tests/dictionaries/80condition_without_target/00-base.xml
@@ -0,0 +1,27 @@
+
+
+
+
+
+ non
+
+
+ non
+
+
+ non
+
+
+ non
+
+
+
+
+
+
+ oui
+
+
+
+
diff --git a/tests/dictionaries/80condition_without_target/__init__.py b/tests/dictionaries/80condition_without_target/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80condition_without_target/errno_9 b/tests/dictionaries/80condition_without_target/errno_9
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80family_dynamic_calc_invalid_suffix/00-base.xml b/tests/dictionaries/80family_dynamic_calc_invalid_suffix/00-base.xml
new file mode 100644
index 00000000..10766b76
--- /dev/null
+++ b/tests/dictionaries/80family_dynamic_calc_invalid_suffix/00-base.xml
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+ val1
+ val2
+
+
+
+
+ val
+
+
+
+
+
+
+
+
+ unknown
+
+
+
diff --git a/tests/dictionaries/80family_dynamic_calc_invalid_suffix/__init__.py b/tests/dictionaries/80family_dynamic_calc_invalid_suffix/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80family_dynamic_calc_invalid_suffix/errno_28 b/tests/dictionaries/80family_dynamic_calc_invalid_suffix/errno_28
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80family_dynamic_not_multi/00-base.xml b/tests/dictionaries/80family_dynamic_not_multi/00-base.xml
new file mode 100644
index 00000000..b8871d57
--- /dev/null
+++ b/tests/dictionaries/80family_dynamic_not_multi/00-base.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
+ val1
+
+
+
+
+
+
+
diff --git a/tests/dictionaries/80family_dynamic_not_multi/__init__.py b/tests/dictionaries/80family_dynamic_not_multi/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80family_dynamic_not_multi/errno_16 b/tests/dictionaries/80family_dynamic_not_multi/errno_16
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80family_only_on_suffix/00-base.xml b/tests/dictionaries/80family_only_on_suffix/00-base.xml
new file mode 100644
index 00000000..7fac5b7d
--- /dev/null
+++ b/tests/dictionaries/80family_only_on_suffix/00-base.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+ val1
+ val2
+
+
+
+
+
+
+
+
+ value
+
+
+
diff --git a/tests/dictionaries/80family_only_on_suffix/__init__.py b/tests/dictionaries/80family_only_on_suffix/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80family_only_on_suffix/errno_26 b/tests/dictionaries/80family_only_on_suffix/errno_26
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80fill_not_exists/00-base.xml b/tests/dictionaries/80fill_not_exists/00-base.xml
new file mode 100644
index 00000000..f1e179c3
--- /dev/null
+++ b/tests/dictionaries/80fill_not_exists/00-base.xml
@@ -0,0 +1,23 @@
+
+
+
+
+
+ non
+
+
+ non
+
+
+
+
+
+
+ mode_conteneur_actif4
+ mode_conteneur_actif1
+ mode_conteneur_actif3
+
+
+
+
diff --git a/tests/dictionaries/80fill_not_exists/__init__.py b/tests/dictionaries/80fill_not_exists/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80fill_not_exists/errno_42 b/tests/dictionaries/80fill_not_exists/errno_42
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80fill_unknown_function/00-base.xml b/tests/dictionaries/80fill_unknown_function/00-base.xml
new file mode 100644
index 00000000..46757b25
--- /dev/null
+++ b/tests/dictionaries/80fill_unknown_function/00-base.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+ non
+
+
+
+
+
+
+ mode_conteneur_actif1
+
+
+
+
diff --git a/tests/dictionaries/80fill_unknown_function/__init__.py b/tests/dictionaries/80fill_unknown_function/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80fill_unknown_function/errno_25 b/tests/dictionaries/80fill_unknown_function/errno_25
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80hidden_if_in_dynamic/00-base.xml b/tests/dictionaries/80hidden_if_in_dynamic/00-base.xml
new file mode 100644
index 00000000..ed1e19e6
--- /dev/null
+++ b/tests/dictionaries/80hidden_if_in_dynamic/00-base.xml
@@ -0,0 +1,26 @@
+
+
+
+
+
+
+ val1
+ val2
+
+
+
+
+ val
+
+
+
+
+
+
+
+
+ non
+ new
+
+
+
diff --git a/tests/dictionaries/80hidden_if_in_dynamic/__init__.py b/tests/dictionaries/80hidden_if_in_dynamic/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80hidden_if_in_dynamic/errno_20 b/tests/dictionaries/80hidden_if_in_dynamic/errno_20
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80valid_entier_invalid_param/00-base.xml b/tests/dictionaries/80valid_entier_invalid_param/00-base.xml
new file mode 100644
index 00000000..feba4a36
--- /dev/null
+++ b/tests/dictionaries/80valid_entier_invalid_param/00-base.xml
@@ -0,0 +1,19 @@
+
+
+
+
+
+ b
+
+
+
+
+
+
+
+ 0
+
+
+
+
diff --git a/tests/dictionaries/80valid_entier_invalid_param/__init__.py b/tests/dictionaries/80valid_entier_invalid_param/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80valid_entier_invalid_param/errno_19 b/tests/dictionaries/80valid_entier_invalid_param/errno_19
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80valid_entier_not_number/00-base.xml b/tests/dictionaries/80valid_entier_not_number/00-base.xml
new file mode 100644
index 00000000..9c527301
--- /dev/null
+++ b/tests/dictionaries/80valid_entier_not_number/00-base.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+ b
+
+
+
+
+
+
+
+ 0
+ 100
+
+
+
+
diff --git a/tests/dictionaries/80valid_entier_not_number/__init__.py b/tests/dictionaries/80valid_entier_not_number/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80valid_entier_not_number/errno_18 b/tests/dictionaries/80valid_entier_not_number/errno_18
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80valid_entier_without_param/00-base.xml b/tests/dictionaries/80valid_entier_without_param/00-base.xml
new file mode 100644
index 00000000..bba116f0
--- /dev/null
+++ b/tests/dictionaries/80valid_entier_without_param/00-base.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+ b
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/dictionaries/80valid_entier_without_param/__init__.py b/tests/dictionaries/80valid_entier_without_param/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80valid_entier_without_param/errno_17 b/tests/dictionaries/80valid_entier_without_param/errno_17
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/80valid_enum_multi_param/errno_5 b/tests/dictionaries/80valid_enum_multi_param/errno_5
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/88valid_enum_not_number2/00-base.xml b/tests/dictionaries/88valid_enum_not_number2/00-base.xml
new file mode 100644
index 00000000..65dbcef1
--- /dev/null
+++ b/tests/dictionaries/88valid_enum_not_number2/00-base.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+ non
+
+
+
+
+ non
+
+
+
+
+
+
+
+ 1
+
+
+
+
diff --git a/tests/dictionaries/88valid_enum_not_number2/__init__.py b/tests/dictionaries/88valid_enum_not_number2/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/88valid_enum_not_number2/errno_7 b/tests/dictionaries/88valid_enum_not_number2/errno_7
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/88valid_enum_variable_optional/00-base.xml b/tests/dictionaries/88valid_enum_variable_optional/00-base.xml
new file mode 100644
index 00000000..bca1ec01
--- /dev/null
+++ b/tests/dictionaries/88valid_enum_variable_optional/00-base.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+ a
+
+
+ a
+ b
+ c
+
+
+
+
+
+ var
+
+
+
+
diff --git a/tests/dictionaries/88valid_enum_variable_optional/__init__.py b/tests/dictionaries/88valid_enum_variable_optional/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/dictionaries/88valid_enum_variable_optional/errno_14 b/tests/dictionaries/88valid_enum_variable_optional/errno_14
new file mode 100644
index 00000000..e69de29b
diff --git a/tests/test_2_makedict.py b/tests/test_2_makedict.py
index e70525a8..617cbe7b 100644
--- a/tests/test_2_makedict.py
+++ b/tests/test_2_makedict.py
@@ -47,7 +47,7 @@ async def launch_flattener(test_dir):
await config.property.read_only()
await config.property.pop('mandatory')
await config.information.set('info', 'value')
- config_dict = await config.value.dict()
+ config_dict = await config.value.dict(leader_to_list=True)
if config_dict:
if not isdir(makedict_dir):
mkdir(makedict_dir)
diff --git a/tests/test_3_template.py b/tests/test_3_template.py
index bbb0d944..549071d5 100644
--- a/tests/test_3_template.py
+++ b/tests/test_3_template.py
@@ -13,7 +13,7 @@ excludes = set([])
#excludes = set(['01base_file_utfchar'])
test_ok = {f for f in listdir(template_dirs) if not f.startswith('_') and isdir(join(template_dirs, f, 'tmpl'))}
test_ok -= excludes
-#test_ok = ['60extra_group']
+#test_ok = ['40ifin_leadershipauto']
@fixture(scope="module", params=test_ok)