diff --git a/src/rougail/annotator.py b/src/rougail/annotator.py
index 5d529bf27..1cfd34fec 100644
--- a/src/rougail/annotator.py
+++ b/src/rougail/annotator.py
@@ -166,7 +166,7 @@ class GroupAnnotator:
)
has_a_leader = True
else:
- raise DictConsistencyError(_('cannot found followers {}').format(follower_names))
+ raise DictConsistencyError(_('cannot found followers "{}"').format('", "'.join(follower_names)))
del self.objectspace.space.constraints.group
def manage_leader(self,
@@ -464,8 +464,7 @@ class ServiceAnnotator:
if not hasattr(file_, 'source'):
file_.source = basename(file_.name)
elif not hasattr(file_, 'source'):
- raise DictConsistencyError(_('attribute source mandatory for file with variable name '
- 'for {}').format(file_.name))
+ raise DictConsistencyError(_('attribute source mandatory for file with variable name for {}').format(file_.name))
class VariableAnnotator:
@@ -789,13 +788,15 @@ class ConstraintAnnotator:
if condition.source == target.name:
raise DictConsistencyError(_('target name and source name must be different: {}').format(condition.source))
try:
- target.name = self.objectspace.paths.get_variable_path(target.name, namespace)
+ 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:
# for optional variable
pass
elif target.type == 'family':
try:
- target.name = self.objectspace.paths.get_family_path(target.name, namespace)
+ target_names = [normalize_family(name) for name in target.name.split('.')]
+ target.name = self.objectspace.paths.get_family_path('.'.join(target_names), namespace)
except KeyError:
raise DictConsistencyError(_('cannot found family {}').format(target.name))
diff --git a/src/rougail/objspace.py b/src/rougail/objspace.py
index eccf50e47..e485b3ad7 100644
--- a/src/rougail/objspace.py
+++ b/src/rougail/objspace.py
@@ -292,6 +292,8 @@ class CreoleObjSpace:
name = child.text
else:
name = subspace['name']
+ if child.tag == 'family':
+ name = normalize_family(name)
existed_var = self.is_already_exists(name,
space,
child,
@@ -362,13 +364,9 @@ class CreoleObjSpace:
if self.paths.path_is_defined(name):
return self.paths.get_variable_obj(name)
return
- if child.tag == 'family':
- norm_name = normalize_family(name)
- else:
- norm_name = name
children = getattr(space, child.tag, {})
- if norm_name in children:
- return children[norm_name]
+ if name in children:
+ return children[name]
def convert_boolean(self, value): # pylint: disable=R0201
"""Boolean coercion. The Creole XML may contain srings like `True` or `False`
@@ -389,19 +387,15 @@ class CreoleObjSpace:
namespace,
):
if not isinstance(family, self.family): # pylint: disable=E1101
- if variable.tag == 'family':
- norm_name = normalize_family(name)
- else:
- norm_name = name
- return getattr(family, variable.tag)[norm_name]
+ return getattr(family, variable.tag)[name]
if namespace == Config['variable_namespace']:
path = name
else:
path = family.path + '.' + name
old_family_name = self.paths.get_variable_family_name(path)
- if normalize_family(family.name) == old_family_name:
+ if family.path == old_family_name:
return getattr(family, variable.tag)[name]
- old_family = self.space.variables[Config['variable_namespace']].family[old_family_name] # pylint: disable=E1101
+ old_family = self.space.variables[namespace].family[old_family_name] # pylint: disable=E1101
variable_obj = old_family.variable[name]
del old_family.variable[name]
if 'variable' not in vars(family):
@@ -541,12 +535,14 @@ class CreoleObjSpace:
if isinstance(space, self.help): # pylint: disable=E1101
return
if child.tag == 'variable':
- family_name = normalize_family(document.attrib['name'])
+ family_name = document.attrib['name']
+ family_name = normalize_family(family_name)
self.paths.add_variable(namespace,
child.attrib['name'],
family_name,
document.attrib.get('dynamic') != None,
- variableobj)
+ variableobj,
+ )
if child.attrib.get('redefine', 'False') == 'True':
if namespace == Config['variable_namespace']:
self.redefine_variables.append(child.attrib['name'])
diff --git a/src/rougail/path.py b/src/rougail/path.py
index 16123fabf..00abc9598 100644
--- a/src/rougail/path.py
+++ b/src/rougail/path.py
@@ -38,10 +38,7 @@ class Path:
name: str,
current_namespace: str,
) -> str: # pylint: disable=C0111
- name = normalize_family(name,
- check_name=False,
- allow_dot=True,
- )
+ #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
diff --git a/src/rougail/tiramisu.py b/src/rougail/tiramisu.py
index 44b3d2599..f09f297df 100644
--- a/src/rougail/tiramisu.py
+++ b/src/rougail/tiramisu.py
@@ -9,5 +9,4 @@ class ConvertDynOptionDescription(DynOptionDescription):
def convert_suffix_to_path(self, suffix):
if not isinstance(suffix, str):
suffix = str(suffix)
- return normalize_family(suffix,
- check_name=False)
+ return normalize_family(suffix)
diff --git a/src/rougail/utils.py b/src/rougail/utils.py
index fd90d31cc..d430d0b56 100644
--- a/src/rougail/utils.py
+++ b/src/rougail/utils.py
@@ -1,23 +1,19 @@
"""
utilitaires créole
"""
-import unicodedata
+from unicodedata import normalize, combining
from .i18n import _
-def normalize_family(family_name: str,
- check_name: bool=True,
- allow_dot: bool=False) -> str:
+def valid_name(name: str) -> None:
+ if '.' in name:
+ raise ValueError(_(f'"{name}" is a forbidden variable or family name, dot is not allowed'))
+
+
+def normalize_family(family_name: str) -> str:
"""replace space, accent, uppercase, ... by valid character
"""
- family_name = family_name.replace('-', '_')
- if not allow_dot:
- family_name = family_name.replace('.', '_')
- family_name = family_name.replace(' ', '_')
- nfkd_form = unicodedata.normalize('NFKD', family_name)
- family_name = ''.join([c for c in nfkd_form if not unicodedata.combining(c)])
- family_name = family_name.lower()
- if check_name and family_name == 'containers':
- raise ValueError(_(f'"{family_name}" is a forbidden family name'))
- return family_name
-
+ family_name = family_name.replace('-', '_').replace(' ', '_').replace('.', '_')
+ nfkd_form = normalize('NFKD', family_name)
+ family_name = ''.join([c for c in nfkd_form if not combining(c)])
+ return family_name.lower()
diff --git a/tests/dictionaries/10load_leadership_normalize_family/00-base.xml b/tests/dictionaries/10load_leadership_normalize_family/00-base.xml
index c68db10eb..eedee1d09 100644
--- a/tests/dictionaries/10load_leadership_normalize_family/00-base.xml
+++ b/tests/dictionaries/10load_leadership_normalize_family/00-base.xml
@@ -1,8 +1,5 @@
-
-
-
@@ -15,14 +12,10 @@
-
follower1
follower2
-
-
-
diff --git a/tests/dictionaries/10load_leadership_normalize_family/01-base.xml b/tests/dictionaries/10load_leadership_normalize_family/01-base.xml
index d0926cce3..b770c714b 100644
--- a/tests/dictionaries/10load_leadership_normalize_family/01-base.xml
+++ b/tests/dictionaries/10load_leadership_normalize_family/01-base.xml
@@ -1,17 +1,8 @@
-
-
-
-
-
-
-
-
-
diff --git a/tests/dictionaries/60extra_redefine/tiramisu/base.py b/tests/dictionaries/60extra_redefine/tiramisu/base.py
index 2af3c2906..8703416c7 100644
--- a/tests/dictionaries/60extra_redefine/tiramisu/base.py
+++ b/tests/dictionaries/60extra_redefine/tiramisu/base.py
@@ -12,9 +12,9 @@ option_3 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen
option_4 = ChoiceOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='activer_ejabberd', doc='No change', multi=False, default='non', values=('oui', 'non'))
option_2 = OptionDescription(name='general', doc='général', properties=frozenset({'normal'}), children=[option_3, option_4])
option_1 = OptionDescription(name='rougail', doc='rougail', children=[option_2])
-option_7 = StrOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='description', doc='description', multi=False, default='Exportation de la base de ejabberd')
-option_8 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='day', doc='day', multi=False, default=Calculation(func.calc_multi_condition, Params((ParamValue("non")), kwargs={'condition_1': ParamOption(option_4, notraisepropertyerror=True, todict=False), 'match': ParamValue("none"), 'mismatch': ParamValue("daily")})), values=('none', 'daily', 'weekly', 'monthly'))
-option_9 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode', doc='mode', multi=False, default='pre', values=('pre', 'post'))
+option_7 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='day', doc='day', multi=False, default=Calculation(func.calc_multi_condition, Params((ParamValue("non")), kwargs={'condition_1': ParamOption(option_4, notraisepropertyerror=True, todict=False), 'match': ParamValue("none"), 'mismatch': ParamValue("daily")})), values=('none', 'daily', 'weekly', 'monthly'))
+option_8 = ChoiceOption(properties=frozenset({'mandatory', 'normal'}), name='mode', doc='mode', multi=False, default='pre', values=('pre', 'post'))
+option_9 = StrOption(properties=frozenset({'force_default_on_freeze', 'frozen', 'hidden', 'mandatory', 'normal'}), name='description', doc='description', multi=False, default='Exportation de la base de ejabberd')
option_6 = OptionDescription(name='ejabberd', doc='ejabberd', properties=frozenset({'normal'}), children=[option_7, option_8, option_9])
option_5 = OptionDescription(name='extra', doc='extra', children=[option_6])
option_0 = OptionDescription(name='baseoption', doc='baseoption', children=[option_1, option_5])