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])