diff --git a/src/rougail/annotator/constrainte.py b/src/rougail/annotator/constrainte.py index 82550473..287f7313 100644 --- a/src/rougail/annotator/constrainte.py +++ b/src/rougail/annotator/constrainte.py @@ -6,7 +6,6 @@ from typing import List, Any from .variable import CONVERT_OPTION from ..i18n import _ -from ..utils import normalize_family from ..error import DictConsistencyError from ..config import Config @@ -61,7 +60,7 @@ class ConstrainteAnnotator: if hasattr(self.objectspace.space.constraints, 'condition'): self.convert_condition_target() self.convert_xxxlist_to_variable() - self.check_condition_fallback_optional() + self.check_condition_fallback() self.convert_condition_source() self.check_choice_option_condition() self.remove_condition_with_empty_target() @@ -271,18 +270,17 @@ class ConstrainteAnnotator: target, ): if target.type == 'variable': - variable = self.objectspace.paths.get_variable_obj(target.name) + if not self.objectspace.paths.is_leader(target.name.path): + return target.name, [target.name] # it's a leader, so apply property to leadership - if self.objectspace.paths.is_leader(target.name): - family_name = self.objectspace.paths.get_variable_family_path(target.name) - family = self.objectspace.paths.get_family(target.name.rsplit('.', 1)[0], - variable.namespace, - ) - return family, family.variable - return variable, [variable] + family_name = self.objectspace.paths.get_variable_family_path(target.name.path) + family = self.objectspace.paths.get_family(family_name, + target.name.namespace, + ) + return family, family.variable # it's a family - variable = self.objectspace.paths.get_family(target.name, - None, + variable = self.objectspace.paths.get_family(target.name.path, + target.namespace, ) return variable, list(variable.variable.values()) @@ -295,40 +293,36 @@ class ConstrainteAnnotator: msg = _(f'target is mandatory in a condition for source "{condition.source}" ' f'in {xmlfiles}') raise DictConsistencyError(msg, 9) - for target in condition.target: - if target.type == 'variable': - if condition.source == target.name: - msg = f'target name and source name must be different: {condition.source}' - raise DictConsistencyError(_(msg), 11) - target_names = '.'.join([normalize_family(name) \ - for name in target.name.split('.')]) - try: - target.name, suffix = self.objectspace.paths.get_variable_path(target_names, - condition.namespace, - ) - if suffix: - xmlfiles = self.objectspace.display_xmlfiles(condition.xmlfiles) - msg = _(f'the target "{target.name}" in condition cannot be a dynamic ' - f'variable in {xmlfiles}') - raise DictConsistencyError(msg, 21) - except DictConsistencyError as err: - # for optional variable - if not target.optional or err.errno != 42: - raise err - elif target.type == 'family': - target_path = '.'.join([normalize_family(name) \ - for name in target.name.split('.')]) - if not self.objectspace.paths.family_is_defined(target_path, - condition.namespace, - ): - raise DictConsistencyError(_(f'cannot found family {target.name}'), 12) - target.name = target_path - elif target.type.endswith('list') and \ - condition.name not in ['disabled_if_in', 'disabled_if_not_in']: - xmlfiles = self.objectspace.display_xmlfiles(target.xmlfiles) - msg = _(f'target "{target.type}" not allow in condition "{condition.name}" ' - f'in {xmlfiles}') - raise DictConsistencyError(msg, 10) + remove_targets = [] + for index, target in enumerate(condition.target): + try: + if target.type == 'variable': + if condition.source == target.name: + msg = f'target name and source name must be different: {condition.source}' + raise DictConsistencyError(_(msg), 11) + target.name = self.objectspace.paths.get_variable_obj(target.name) + elif target.type == 'family': + target.name = self.objectspace.paths.get_family(target.name, + condition.namespace, + ) + elif target.type.endswith('list') and \ + condition.name not in ['disabled_if_in', 'disabled_if_not_in']: + xmlfiles = self.objectspace.display_xmlfiles(target.xmlfiles) + msg = _(f'target "{target.type}" not allow in condition "{condition.name}" ' + f'in {xmlfiles}') + raise DictConsistencyError(msg, 10) + except DictConsistencyError as err: + if err.errno != 42: + raise err + # for optional variable + if not target.optional: + xmlfiles = self.objectspace.display_xmlfiles(condition.xmlfiles) + raise DictConsistencyError(_(f'cannot found target "{target.name}" in the condition in {xmlfiles}'), 12) + remove_targets.append(index) + remove_targets.sort(reverse=True) + for index in remove_targets: + condition.target.pop(index) + def convert_xxxlist_to_variable(self): """transform *list to variable or family @@ -343,9 +337,8 @@ class ConstrainteAnnotator: {}).get(target.name) if listvars: for listvar in listvars: - variable = self.objectspace.paths.get_variable_obj(listvar) type_ = 'variable' - new_target = self.objectspace.target(variable.xmlfiles) + new_target = self.objectspace.target(listvar.xmlfiles) new_target.type = type_ new_target.name = listvar new_targets.append(new_target) @@ -355,7 +348,7 @@ class ConstrainteAnnotator: condition.target.pop(target_idx) condition.target.extend(new_targets) - def check_condition_fallback_optional(self): + def check_condition_fallback(self): """a condition with a fallback **and** the source variable doesn't exist """ remove_conditions = [] @@ -371,18 +364,6 @@ class ConstrainteAnnotator: remove_conditions.append(idx) if apply_action: self.force_actions_to_variable(condition) - continue - - remove_targets = [] - # optional - for index, target in enumerate(condition.target): - if target.optional is True and \ - not self.objectspace.paths.path_is_defined(target.name): - remove_targets.append(index) - remove_targets = list(set(remove_targets)) - remove_targets.sort(reverse=True) - for index in remove_targets: - condition.target.pop(index) remove_conditions = list(set(remove_conditions)) remove_conditions.sort(reverse=True) for idx in remove_conditions: diff --git a/src/rougail/annotator/service.py b/src/rougail/annotator/service.py index 3af9d6a8..bc207e68 100644 --- a/src/rougail/annotator/service.py +++ b/src/rougail/annotator/service.py @@ -84,6 +84,7 @@ class ServiceAnnotator: and build elements and its attributes (the `Options` in tiramisu terms) """ families = [] + listname = '{}list'.format(elttype) for elt in elts: # try to launch _update_xxxx() function update_elt = '_update_' + elttype @@ -99,17 +100,21 @@ class ServiceAnnotator: elt.xmlfiles, ) family.variable = [] - activate_path = '.'.join([subpath, 'activate']) + activate_obj = self._generate_element('boolean', + 'activate', + True, + elt.xmlfiles, + '.'.join([subpath, 'activate']), + ) for key in dir(elt): if key.startswith('_') or key.endswith('_type') or key in ERASED_ATTRIBUTES: continue value = getattr(elt, key) - listname = '{}list'.format(elttype) if key == listname: self.objectspace.list_conditions.setdefault(listname, {}).setdefault( value, - []).append(activate_path) + []).append(activate_obj) continue family.variable.append(self._generate_element(self._get_type(key, elttype, @@ -122,12 +127,7 @@ class ServiceAnnotator: )) # FIXME ne devrait pas etre True par défaut # devrait etre un calcule - family.variable.append(self._generate_element('boolean', - 'activate', - True, - elt.xmlfiles, - activate_path, - )) + family.variable.append(activate_obj) families.append(family) return families @@ -146,8 +146,11 @@ class ServiceAnnotator: if idx: c_name += f'_{idx}' subpath = '{}.{}'.format(path, c_name) - if not self.objectspace.paths.family_is_defined(subpath, 'services'): - return c_name, subpath + try: + self.objectspace.paths.get_family(subpath, 'services') + except DictConsistencyError as err: + if err.errno == 42: + return c_name, subpath idx += 1 def _gen_family(self, diff --git a/src/rougail/path.py b/src/rougail/path.py index 8d953d35..429ba8ee 100644 --- a/src/rougail/path.py +++ b/src/rougail/path.py @@ -1,6 +1,7 @@ from .i18n import _ from .error import DictConsistencyError from .config import Config +from .utils import normalize_family class Path: @@ -48,33 +49,19 @@ class Path: ) variableobj.path = path - 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(self, name: str, - namespace: str, + current_namespace: str, ) -> 'Family': # pylint: disable=C0111 - return self._get_family(name, namespace)['variableobj'] - - def family_is_defined(self, - name: str, - namespace: str, - ) -> str: # pylint: disable=C0111 - try: - self._get_family(name, namespace) - return True - except KeyError: - return False + name = '.'.join([normalize_family(subname) for subname in name.split('.')]) + if name not in self.families and name in self.full_paths_families: + name = self.full_paths_families[name] + if name not in self.families: + raise DictConsistencyError(_('unknown option {}').format(name), 42) + dico = self.families[name] + if current_namespace not in [Config['variable_namespace'], 'services'] 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['variableobj'] # Leadership def set_leader(self, @@ -142,13 +129,12 @@ class Path: def get_variable_path(self, name: str, current_namespace: str, - allow_variable_namespace: str=False, ) -> str: # pylint: disable=C0111 dico, suffix = self._get_variable(name, with_suffix=True, ) namespace = dico['variableobj'].namespace - if not allow_variable_namespace and namespace not in [Config['variable_namespace'], 'services'] and current_namespace != namespace: + if namespace not in [Config['variable_namespace'], 'services'] and current_namespace != namespace: raise DictConsistencyError(_(f'A variable located in the "{namespace}" namespace shall not be used in the "{current_namespace}" namespace'), 41) return dico['variableobj'].path, suffix @@ -168,6 +154,7 @@ class Path: name: str, with_suffix: bool=False, ) -> str: + name = '.'.join([normalize_family(subname) for subname in name.split('.')]) if name not in self.variables: if '.' not in name and name in self.full_paths_variables: name = self.full_paths_variables[name] diff --git a/tests/dictionaries/60extra_externalspacecondition3/errno_12 b/tests/dictionaries/60extra_externalspacecondition3/errno_38 similarity index 100% rename from tests/dictionaries/60extra_externalspacecondition3/errno_12 rename to tests/dictionaries/60extra_externalspacecondition3/errno_38 diff --git a/tests/dictionaries/80condition_not_exists_error_var/errno_42 b/tests/dictionaries/80condition_not_exists_error_var/errno_12 similarity index 100% rename from tests/dictionaries/80condition_not_exists_error_var/errno_42 rename to tests/dictionaries/80condition_not_exists_error_var/errno_12