diff --git a/src/rougail/annotator/constrainte.py b/src/rougail/annotator/constrainte.py index 6c81202a..a65f6a45 100644 --- a/src/rougail/annotator/constrainte.py +++ b/src/rougail/annotator/constrainte.py @@ -6,6 +6,10 @@ from .variable import CONVERT_OPTION from ..i18n import _ from ..utils import normalize_family from ..error import DictConsistencyError +from ..config import Config + +FREEZE_AUTOFREEZE_VARIABLE = 'module_instancie' + INTERNAL_FUNCTIONS = ['valid_enum', 'valid_in_network', 'valid_differ', 'valid_entier'] @@ -20,6 +24,8 @@ class ConstrainteAnnotator: eosfunc = SourceFileLoader('eosfunc', eosfunc_file).load_module() self.functions = dir(eosfunc) self.functions.extend(INTERNAL_FUNCTIONS) + + self.convert_auto_freeze() self.valid_enums = {} if hasattr(self.objectspace.space.constraints, 'check'): self.check_check() @@ -39,12 +45,46 @@ class ConstrainteAnnotator: self.convert_fill() 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']: + xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles) + raise DictConsistencyError(_(f'auto_freeze is not allowed in extra "{namespace}" in {xmlfiles}'), 49) + new_condition = self.objectspace.condition(variable.xmlfiles) + new_condition.name = 'auto_hidden_if_not_in' + new_condition.namespace = namespace + new_condition.source = FREEZE_AUTOFREEZE_VARIABLE + new_param = self.objectspace.param(variable.xmlfiles) + new_param.text = 'oui' + new_condition.param = [new_param] + new_target = self.objectspace.target(variable.xmlfiles) + new_target.type = 'variable' + new_target.name = variable.name + new_condition.target = [new_target] + if not hasattr(self.objectspace.space.constraints, 'condition'): + self.objectspace.space.constraints.condition = [] + self.objectspace.space.constraints.condition.append(new_condition) + for variables in self.objectspace.space.variables.values(): + if hasattr(variables, 'family'): + namespace = variables.name + for family in variables.family.values(): + if hasattr(family, 'variable'): + for variable in family.variable.values(): + if isinstance(variable, self.objectspace.leadership): + for follower in variable.variable: + _convert_auto_freeze(follower, namespace) + else: + _convert_auto_freeze(variable, namespace) + def check_check(self): remove_indexes = [] for check_idx, check in enumerate(self.objectspace.space.constraints.check): if not check.name in self.functions: xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles) - raise DictConsistencyError(_(f'cannot find check function "{check.name}" in {xmlfiles}')) + raise DictConsistencyError(_(f'cannot find check function "{check.name}" in {xmlfiles}'), 1) if hasattr(check, 'param'): param_option_indexes = [] for idx, param in enumerate(check.param): @@ -53,7 +93,7 @@ class ConstrainteAnnotator: param_option_indexes.append(idx) else: xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles) - raise DictConsistencyError(_(f'cannot find check param "{param.text}" in {xmlfiles}')) + raise DictConsistencyError(_(f'cannot find check param "{param.text}" in {xmlfiles}'), 2) if param.type != 'variable': param.notraisepropertyerror = None param_option_indexes = list(set(param_option_indexes)) @@ -84,9 +124,9 @@ class ConstrainteAnnotator: if check.target in self.valid_enums: old_xmlfiles = self.objectspace.display_xmlfiles(self.valid_enums[check.target]['xmlfiles']) xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles) - raise DictConsistencyError(_(f'valid_enum define in {xmlfiles} but already set in {old_xmlfiles} for "{check.target}", did you forget remove_check?')) + raise DictConsistencyError(_(f'valid_enum define in {xmlfiles} but already set in {old_xmlfiles} for "{check.target}", did you forget remove_check?'), 3) if not hasattr(check, 'param'): - raise DictConsistencyError(_(f'param is mandatory for a valid_enum of variable {check.target}')) + raise DictConsistencyError(_(f'param is mandatory for a valid_enum of variable {check.target}'), 4) variable = self.objectspace.paths.get_variable_obj(check.target) values = self.load_params_in_valid_enum(check.param, variable.name, @@ -113,18 +153,18 @@ class ConstrainteAnnotator: for param in params: if param.type == 'variable': if has_variable is not None: - raise DictConsistencyError(_(f'only one "variable" parameter is allowed for valid_enum of variable {variable_name}')) + raise DictConsistencyError(_(f'only one "variable" parameter is allowed for valid_enum of variable {variable_name}'), 5) has_variable = True variable = self.objectspace.paths.get_variable_obj(param.text) if not variable.multi: - raise DictConsistencyError(_(f'only multi "variable" parameter is allowed for valid_enum of variable {variable_name}')) + raise DictConsistencyError(_(f'only multi "variable" parameter is allowed for valid_enum of variable {variable_name}'), 6) values = param.text else: if has_variable: - raise DictConsistencyError(_(f'only one "variable" parameter is allowed for valid_enum of variable {variable_name}')) + raise DictConsistencyError(_(f'only one "variable" parameter is allowed for valid_enum of variable {variable_name}'), 7) if not hasattr(param, 'text'): if param.type == 'number': - raise DictConsistencyError(_(f'value is mandatory for valid_enum of variable {variable_name}')) + raise DictConsistencyError(_(f'value is mandatory for valid_enum of variable {variable_name}'), 8) values.append(None) else: values.append(param.text) @@ -156,10 +196,11 @@ 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')) + raise DictConsistencyError(_('target is mandatory in condition'), 9) for target in condition.target: if target.type.endswith('list') and condition.name not in ['disabled_if_in', 'disabled_if_not_in']: - raise DictConsistencyError(_(f'target in condition for {target.type} not allow in {condition.name}')) + xmlfiles = self.objectspace.display_xmlfiles(target.xmlfiles) + raise DictConsistencyError(_(f'target "{target.type}" not allow in condition "{condition.name}" in {xmlfiles}'), 10) def filter_targets(self): # pylint: disable=C0111 for condition_idx, condition in enumerate(self.objectspace.space.constraints.condition): @@ -167,7 +208,7 @@ class ConstrainteAnnotator: for idx, target in enumerate(condition.target): if target.type == 'variable': if condition.source == target.name: - raise DictConsistencyError(_('target name and source name must be different: {}').format(condition.source)) + raise DictConsistencyError(_('target name and source name must be different: {}').format(condition.source), 11) try: target_names = [normalize_family(name) for name in target.name.split('.')] target.name = self.objectspace.paths.get_variable_path('.'.join(target_names), namespace) @@ -179,7 +220,7 @@ class ConstrainteAnnotator: 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)) + raise DictConsistencyError(_('cannot found family {}').format(target.name), 12) def convert_xxxlist_to_variable(self): # pylint: disable=C0111 # transform *list to variable or family @@ -318,6 +359,11 @@ class ConstrainteAnnotator: main_action = actions[0] if getattr(leader_or_variable, main_action, False) is True: continue + if isinstance(leader_or_variable, self.objectspace.variable) and \ + (leader_or_variable.auto_save or leader_or_variable.auto_freeze) and \ + 'force_default_on_freeze' in actions: + xmlfiles = self.objectspace.display_xmlfiles(leader_or_variable.xmlfiles) + raise DictConsistencyError(_(f'cannot have auto_freeze or auto_store with the hidden_if_in or hidden_if_not_in variable "{leader_or_variable.name}" in {xmlfiles}'), 51) for idx, action in enumerate(actions): prop = self.objectspace.property_(leader_or_variable.xmlfiles) prop.type = 'calculation' @@ -368,7 +414,7 @@ class ConstrainteAnnotator: 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}"')) + 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) @@ -381,16 +427,16 @@ class ConstrainteAnnotator: 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}"')) + 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)) + 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)) + raise DictConsistencyError(_('empty valid enum is not allowed for variable {}').format(variable.name), 16) variable.type = 'choice' def convert_check(self): @@ -399,16 +445,16 @@ class ConstrainteAnnotator: name = check.name if name == 'valid_entier': if not hasattr(check, 'param'): - raise DictConsistencyError(_('{} must have, at least, 1 param').format(name)) + 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}"')) + raise DictConsistencyError(_(f'param in "valid_entier" must not be a "{param.type}"'), 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}')) + raise DictConsistencyError(_(f'unknown parameter {param.text} in check "valid_entier" for variable {check.target}'), 19) else: check_ = self.objectspace.check(variable.xmlfiles) if name == 'valid_differ': @@ -417,23 +463,23 @@ class ConstrainteAnnotator: 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}')) + 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}')) + 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}')) + 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}')) + 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'): @@ -454,11 +500,11 @@ class ConstrainteAnnotator: # test if it's redefined calculation if fill.target in targets: xmlfiles = self.objectspace.display_xmlfiles(fill.xmlfiles) - raise DictConsistencyError(_(f'A fill already exists for the target of "{fill.target}" created in {xmlfiles}')) + raise DictConsistencyError(_(f'A fill already exists for the target of "{fill.target}" created in {xmlfiles}'), 24) targets.append(fill.target) # if fill.name not in self.functions: - raise DictConsistencyError(_('cannot find fill function {}').format(fill.name)) + raise DictConsistencyError(_('cannot find fill function {}').format(fill.name), 25) namespace = fill.namespace # let's replace the target by the path @@ -467,7 +513,7 @@ class ConstrainteAnnotator: with_suffix=True, ) if suffix is not None: - raise DictConsistencyError(_(f'Cannot add fill function to "{fill.target}" only with the suffix "{suffix}"')) + raise DictConsistencyError(_(f'Cannot add fill function to "{fill.target}" only with the suffix "{suffix}"'), 26) variable = self.objectspace.paths.get_variable_obj(fill.target) value = self.objectspace.value(variable.xmlfiles) value.type = 'calculation' @@ -476,9 +522,9 @@ class ConstrainteAnnotator: param_to_delete = [] for fill_idx, param in enumerate(fill.param): if param.type not in ['suffix', 'string'] and not hasattr(param, 'text'): - raise DictConsistencyError(_(f"All '{param.type}' variables must have a value in order to calculate {fill.target}")) + raise DictConsistencyError(_(f"All '{param.type}' variables must have a value in order to calculate {fill.target}"), 27) if param.type == 'suffix' and hasattr(param, 'text'): - raise DictConsistencyError(_(f"All '{param.type}' variables must not have a value in order to calculate {fill.target}")) + raise DictConsistencyError(_(f"All '{param.type}' variables must not have a value in order to calculate {fill.target}"), 28) if param.type == 'string': if not hasattr(param, 'text'): param.text = None @@ -491,6 +537,8 @@ class ConstrainteAnnotator: if suffix: param.suffix = suffix except DictConsistencyError as err: + if err.errno != 42: + raise err if param.optional is False: raise err param_to_delete.append(fill_idx) diff --git a/src/rougail/annotator/family.py b/src/rougail/annotator/family.py index 78361e00..43d3ceb4 100644 --- a/src/rougail/annotator/family.py +++ b/src/rougail/annotator/family.py @@ -124,9 +124,11 @@ class FamilyAnnotator: mode = modes_level[-1] for idx, follower in enumerate(variable.variable): if follower.auto_save is True: - raise DictConsistencyError(_(f'leader/followers {follower.name} could not be auto_save')) + xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles) + raise DictConsistencyError(_(f'leader/followers "{follower.name}" could not be auto_save in {xmlfiles}'), 29) if follower.auto_freeze is True: - raise DictConsistencyError(_('leader/followers {follower.name} could not be auto_freeze')) + xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles) + raise DictConsistencyError(_(f'leader/followers "{follower.name}" could not be auto_freeze in {xmlfiles}'), 30) is_follower = idx != 0 path = '{}.{}.{}'.format(family.path, variable.name, follower.name) self.annotate_variable(follower, family_mode, path, is_follower) diff --git a/src/rougail/annotator/group.py b/src/rougail/annotator/group.py index 532ba9f3..aaba954a 100644 --- a/src/rougail/annotator/group.py +++ b/src/rougail/annotator/group.py @@ -63,7 +63,9 @@ class GroupAnnotator: ) has_a_leader = True else: - raise DictConsistencyError(_('cannot found followers "{}"').format('", "'.join(follower_names))) + xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles) + joined = '", "'.join(follower_names) + raise DictConsistencyError(_(f'when parsing leadership, we espect to find those followers "{joined}" in {xmlfiles}'), 31) del self.objectspace.space.constraints.group def manage_leader(self, @@ -78,7 +80,8 @@ class GroupAnnotator: ) -> None: # manage leader's variable if variable.multi is not True: - raise DictConsistencyError(_('the variable {} in a group must be multi').format(variable.name)) + xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles) + raise DictConsistencyError(_(f'the variable "{variable.name}" in a group must be multi in {xmlfiles}'), 32) leader_space.variable = [] leader_space.name = leadership_name leader_space.hidden = variable.hidden @@ -121,7 +124,8 @@ class GroupAnnotator: leader_is_hidden: bool, ) -> None: if variable.name != follower_names[0]: - raise DictConsistencyError(_('cannot found this follower {}').format(follower_names[0])) + xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles) + raise DictConsistencyError(_(f'when parsing leadership, we espect to find the follower "{follower_names[0]}" but we found "{variable.name}" in {xmlfiles}'), 33) follower_names.remove(variable.name) if leader_is_hidden: variable.frozen = True diff --git a/src/rougail/annotator/property.py b/src/rougail/annotator/property.py index 741538e3..6a2aebbe 100644 --- a/src/rougail/annotator/property.py +++ b/src/rougail/annotator/property.py @@ -1,3 +1,7 @@ +from ..i18n import _ +from ..error import DictConsistencyError + + PROPERTIES = ('hidden', 'frozen', 'auto_freeze', 'auto_save', 'force_default_on_freeze', 'force_store_value', 'disabled', 'mandatory') CONVERT_PROPERTIES = {'auto_save': ['force_store_value'], 'auto_freeze': ['force_store_value', 'auto_freeze']} @@ -21,6 +25,9 @@ class PropertyAnnotator: if hasattr(variable, 'mode') and variable.mode: properties.append(variable.mode) variable.mode = None + if 'force_store_value' in properties and 'force_default_on_freeze' in properties: + xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles) + raise DictConsistencyError(_(f'cannot have auto_freeze or auto_store with the hidden variable "{variable.name}" in {xmlfiles}'), 50) if properties: variable.properties = frozenset(properties) @@ -52,4 +59,3 @@ class PropertyAnnotator: self.convert_property(follower) else: self.convert_property(variable) - diff --git a/src/rougail/annotator/service.py b/src/rougail/annotator/service.py index e4e72116..c5daabd4 100644 --- a/src/rougail/annotator/service.py +++ b/src/rougail/annotator/service.py @@ -247,5 +247,6 @@ 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)) + xmlfiles = self.objectspace.display_xmlfiles(file_.xmlfiles) + raise DictConsistencyError(_(f'attribute "source" is mandatory for the file "{file_.name}" in {xmlfiles}'), 34) diff --git a/src/rougail/annotator/variable.py b/src/rougail/annotator/variable.py index 69e8b512..e258f60f 100644 --- a/src/rougail/annotator/variable.py +++ b/src/rougail/annotator/variable.py @@ -37,9 +37,6 @@ FORCE_CHOICE = {'oui/non': ['oui', 'non'], 'schedulemod': ['pre', 'post']} -FREEZE_AUTOFREEZE_VARIABLE = 'module_instancie' - - RENAME_ATTIBUTES = {'description': 'doc'} @@ -49,7 +46,6 @@ class VariableAnnotator: ): self.objectspace = objectspace self.convert_variable() - self.convert_auto_freeze() self.convert_separators() def convert_variable(self): @@ -99,7 +95,7 @@ class VariableAnnotator: def _valid_type(variable): if variable.type not in CONVERT_OPTION: xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles) - raise DictConsistencyError(_(f'unvalid type "{variable.type}" for variable "{variable.name}" in {xmlfiles}')) + raise DictConsistencyError(_(f'unvalid type "{variable.type}" for variable "{variable.name}" in {xmlfiles}'), 36) if not hasattr(self.objectspace.space, 'variables'): return @@ -109,10 +105,6 @@ class VariableAnnotator: families.doc = families.name for family in families.family.values(): family.doc = family.name - for key, value in RENAME_ATTIBUTES.items(): - if hasattr(family, key): - setattr(family, value, getattr(family, key)) - setattr(family, key, None) family.name = normalize_family(family.name) if hasattr(family, 'variable'): for variable in family.variable.values(): @@ -142,37 +134,6 @@ class VariableAnnotator: ) _valid_type(variable) - def convert_auto_freeze(self): # pylint: disable=C0111 - def _convert_auto_freeze(variable, namespace): - if variable.auto_freeze: - new_condition = self.objectspace.condition(variable.xmlfiles) - new_condition.name = 'auto_hidden_if_not_in' - new_condition.namespace = namespace - new_condition.source = FREEZE_AUTOFREEZE_VARIABLE - new_param = self.objectspace.param(variable.xmlfiles) - new_param.text = 'oui' - new_condition.param = [new_param] - new_target = self.objectspace.target(variable.xmlfiles) - new_target.type = 'variable' - path = variable.namespace + '.' + normalize_family(family.name) + '.' + variable.name - new_target.name = path - new_condition.target = [new_target] - if not hasattr(self.objectspace.space.constraints, 'condition'): - self.objectspace.space.constraints.condition = [] - self.objectspace.space.constraints.condition.append(new_condition) - if hasattr(self.objectspace.space, 'variables'): - for variables in self.objectspace.space.variables.values(): - if hasattr(variables, 'family'): - namespace = variables.name - for family in variables.family.values(): - if hasattr(family, 'variable'): - for variable in family.variable.values(): - if isinstance(variable, self.objectspace.leadership): - for follower in variable.variable: - _convert_auto_freeze(follower, namespace) - else: - _convert_auto_freeze(variable, namespace) - def convert_separators(self): # pylint: disable=C0111,R0201 if not hasattr(self.objectspace.space, 'variables'): return @@ -187,7 +148,7 @@ class VariableAnnotator: separator.namespace, ) xmlfiles = self.objectspace.display_xmlfiles(separator.xmlfiles) - raise DictConsistencyError(_(f'{subpath} already has a separator in {xmlfiles}')) + raise DictConsistencyError(_(f'{subpath} already has a separator in {xmlfiles}'), 35) option.separator = separator.text del family.separators diff --git a/src/rougail/error.py b/src/rougail/error.py index 221e355f..68252f61 100644 --- a/src/rougail/error.py +++ b/src/rougail/error.py @@ -29,6 +29,9 @@ class DictConsistencyError(Exception): """It's not only that the Creole XML is valid against the Creole DTD it's that it is not consistent. """ + def __init__(self, msg, errno): + super().__init__(msg) + self.errno = errno class LoaderError(Exception): diff --git a/src/rougail/objspace.py b/src/rougail/objspace.py index 0a462bc3..bcb2ac36 100644 --- a/src/rougail/objspace.py +++ b/src/rougail/objspace.py @@ -170,7 +170,7 @@ class RougailObjSpace: continue if child.tag == 'family': if child.attrib['name'] in family_names: - raise DictConsistencyError(_(f'Family "{child.attrib["name"]}" is set several times in "{xmlfile}"')) + raise DictConsistencyError(_(f'Family "{child.attrib["name"]}" is set several times in "{xmlfile}"'), 44) family_names.append(child.attrib['name']) if child.tag == 'variables': # variables has no name, so force namespace name @@ -273,7 +273,7 @@ class RougailObjSpace: if exists is False: raise SpaceObjShallNotBeUpdated() xmlfiles = self.display_xmlfiles(existed_var.xmlfiles) - raise DictConsistencyError(_(f'"{child.tag}" named "{name}" cannot be re-created in "{xmlfile}", already defined in {xmlfiles}')) + raise DictConsistencyError(_(f'"{child.tag}" named "{name}" cannot be re-created in "{xmlfile}", already defined in {xmlfiles}'), 45) # if this object must only be modified if object already exists exists = self.convert_boolean(subspace.get('exists', False)) if exists is True: @@ -283,7 +283,7 @@ class RougailObjSpace: if child.tag not in vars(space): setattr(space, child.tag, {}) return getattr(self, child.tag)(xmlfile) - raise DictConsistencyError(_(f'Redefined object in "{xmlfile}": "{name}" does not exist yet')) + raise DictConsistencyError(_(f'Redefined object in "{xmlfile}": "{name}" does not exist yet'), 46) def get_existed_obj(self, name: str, @@ -301,7 +301,7 @@ class RougailObjSpace: old_family_name = namespace + '.' + old_family_name if space.path != old_family_name: xmlfiles = self.display_xmlfiles(space.xmlfiles) - raise DictConsistencyError(_(f'Variable was previously create in family "{old_family_name}", now it is in "{space.path}" in {xmlfiles}')) + raise DictConsistencyError(_(f'Variable was previously create in family "{old_family_name}", now it is in "{space.path}" in {xmlfiles}'), 47) return self.paths.get_variable_obj(name) children = getattr(space, child.tag, {}) if name in children: @@ -344,7 +344,7 @@ class RougailObjSpace: for attr, val in child.attrib.items(): if redefine and attr in UNREDEFINABLE: xmlfiles = self.display_xmlfiles(variableobj.xmlfiles[:-1]) - raise DictConsistencyError(_(f'cannot redefine attribute "{attr}" for variable "{child.attrib["name"]}" in "{xmlfile}", already defined in {xmlfiles}')) + raise DictConsistencyError(_(f'cannot redefine attribute "{attr}" for variable "{child.attrib["name"]}" in "{xmlfile}", already defined in {xmlfiles}'), 48) if attr in self.booleans_attributs: val = self.convert_boolean(val) if attr == 'name' and getattr(variableobj, 'name', None): diff --git a/src/rougail/path.py b/src/rougail/path.py index 00abc959..b8374b16 100644 --- a/src/rougail/path.py +++ b/src/rougail/path.py @@ -28,7 +28,7 @@ class Path: else: full_name = name if full_name in self.families and self.families[full_name]['variableobj'] != variableobj: - raise DictConsistencyError(_(f'Duplicate family name {name}')) + raise DictConsistencyError(_(f'Duplicate family name {name}'), 37) self.families[full_name] = dict(name=name, namespace=namespace, variableobj=variableobj, @@ -45,9 +45,7 @@ class Path: 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(_('A family located in the {} namespace ' - 'shall not be used in the {} namespace').format( - dico['namespace'], current_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'] def get_family_obj(self, @@ -56,7 +54,7 @@ class Path: 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)) + raise DictConsistencyError(_('unknown family {}').format(name), 39) dico = self.families[name] return dico['variableobj'] @@ -92,7 +90,7 @@ class Path: dico = self._get_variable(name) if dico['leader'] != None: raise DictConsistencyError(_('Already defined leader {} for variable' - ' {}'.format(dico['leader'], name))) + ' {}'.format(dico['leader'], name)), 40) dico['leader'] = leader_name def get_leader(self, name): # pylint: disable=C0111 @@ -156,9 +154,7 @@ class Path: dico = self._get_variable(name) if not allow_source: if dico['namespace'] not in [Config['variable_namespace'], 'services'] and current_namespace != dico['namespace']: - raise DictConsistencyError(_('A variable located in the {} namespace ' - 'shall not be used in the {} namespace').format( - dico['namespace'], current_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: @@ -200,7 +196,7 @@ class Path: 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)) + raise DictConsistencyError(_('unknown option {}').format(name), 42) if with_suffix: return self.variables[name], None return self.variables[name] diff --git a/src/rougail/xmlreflector.py b/src/rougail/xmlreflector.py index a2ebcc90..d6352c71 100644 --- a/src/rougail/xmlreflector.py +++ b/src/rougail/xmlreflector.py @@ -37,7 +37,7 @@ class XMLReflector(object): # document = parse(BytesIO(xmlfile), XMLParser(remove_blank_text=True)) document = parse(xmlfile) if not self.dtd.validate(document): - raise DictConsistencyError(_(f'"{xmlfile}" not a valid xml file: {self.dtd.error_log.filter_from_errors()[0]}')) + raise DictConsistencyError(_(f'"{xmlfile}" not a valid xml file: {self.dtd.error_log.filter_from_errors()[0]}'), 43) return document.getroot() def load_xml_from_folders(self, xmlfolders): diff --git a/tests/dictionaries/10autosave_hidden_frozenifin/makedict/base.json b/tests/dictionaries/10autosave_hidden_frozenifin/makedict/base.json deleted file mode 100644 index 2a8f28f8..00000000 --- a/tests/dictionaries/10autosave_hidden_frozenifin/makedict/base.json +++ /dev/null @@ -1 +0,0 @@ -{"rougail.general.mode_conteneur_actif": "non", "rougail.general.autosavevar": "oui"} diff --git a/tests/dictionaries/10autosave_hidden_frozenifin/tiramisu/base.py b/tests/dictionaries/10autosave_hidden_frozenifin/tiramisu/base.py deleted file mode 100644 index 00ac1625..00000000 --- a/tests/dictionaries/10autosave_hidden_frozenifin/tiramisu/base.py +++ /dev/null @@ -1,15 +0,0 @@ -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='non', values=('oui', 'non')) -option_4 = StrOption(properties=frozenset({'basic', 'force_store_value', Calculation(calc_value, Params(ParamValue('hidden'), kwargs={'condition': ParamOption(option_3, todict=True), 'expected': ParamValue('oui')})), Calculation(calc_value, Params(ParamValue('frozen'), kwargs={'condition': ParamOption(option_3, todict=True), 'expected': ParamValue('oui')})), Calculation(calc_value, Params(ParamValue('force_default_on_freeze'), kwargs={'condition': ParamOption(option_3, todict=True), 'expected': ParamValue('oui')}))}), name='autosavevar', doc='autosave variable', multi=False, default=Calculation(func.calc_val, Params((ParamValue("oui")), kwargs={}))) -option_2 = OptionDescription(name='general', doc='général', properties=frozenset({'basic'}), 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/10autosave_hidden_frozenifin/__init__.py b/tests/dictionaries/51redefine_multi/errno_48 similarity index 100% rename from tests/dictionaries/10autosave_hidden_frozenifin/__init__.py rename to tests/dictionaries/51redefine_multi/errno_48 diff --git a/tests/dictionaries/10autosave_hidden_frozenifin/tiramisu/__init__.py b/tests/dictionaries/51redefine_type/errno_48 similarity index 100% rename from tests/dictionaries/10autosave_hidden_frozenifin/tiramisu/__init__.py rename to tests/dictionaries/51redefine_type/errno_48 diff --git a/tests/dictionaries/80fill_autofreeze/__init__.py b/tests/dictionaries/60extra_externalspace/errno_41 similarity index 100% rename from tests/dictionaries/80fill_autofreeze/__init__.py rename to tests/dictionaries/60extra_externalspace/errno_41 diff --git a/tests/dictionaries/60extra_externalspaceauto/errno_41 b/tests/dictionaries/60extra_externalspaceauto/errno_41 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/60extra_externalspacecondition2/errno_38 b/tests/dictionaries/60extra_externalspacecondition2/errno_38 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/60extra_externalspacecondition3/errno_12 b/tests/dictionaries/60extra_externalspacecondition3/errno_12 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80fill_autofreeze/00-base.xml b/tests/dictionaries/80auto_autofreeze/00-base.xml similarity index 64% rename from tests/dictionaries/80fill_autofreeze/00-base.xml rename to tests/dictionaries/80auto_autofreeze/00-base.xml index a63e8ddc..53f69a83 100644 --- a/tests/dictionaries/80fill_autofreeze/00-base.xml +++ b/tests/dictionaries/80auto_autofreeze/00-base.xml @@ -2,7 +2,10 @@ - + + non + + @@ -10,7 +13,7 @@ - value + oui diff --git a/tests/dictionaries/80auto_autofreeze/__init__.py b/tests/dictionaries/80auto_autofreeze/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80auto_autofreeze/errno_50 b/tests/dictionaries/80auto_autofreeze/errno_50 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/10autosave_hidden_frozenifin/00-base.xml b/tests/dictionaries/80autosave_hidden_frozenifin/00-base.xml similarity index 100% rename from tests/dictionaries/10autosave_hidden_frozenifin/00-base.xml rename to tests/dictionaries/80autosave_hidden_frozenifin/00-base.xml diff --git a/tests/dictionaries/80autosave_hidden_frozenifin/__init__.py b/tests/dictionaries/80autosave_hidden_frozenifin/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80autosave_hidden_frozenifin/errno_51 b/tests/dictionaries/80autosave_hidden_frozenifin/errno_51 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80check_unknown/errno_1 b/tests/dictionaries/80check_unknown/errno_1 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80check_unknown_var/errno_2 b/tests/dictionaries/80check_unknown_var/errno_2 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80condition_itself/errno_11 b/tests/dictionaries/80condition_itself/errno_11 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80condition_not_exists_error/errno_12 b/tests/dictionaries/80condition_not_exists_error/errno_12 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80container_files_symlink_without_source/errno_34 b/tests/dictionaries/80container_files_symlink_without_source/errno_34 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80container_filesredefine_error/errno_45 b/tests/dictionaries/80container_filesredefine_error/errno_45 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80empty_param_number/errno_27 b/tests/dictionaries/80empty_param_number/errno_27 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80empty_typeeole_eole/errno_27 b/tests/dictionaries/80empty_typeeole_eole/errno_27 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80empty_typeeole_number/errno_27 b/tests/dictionaries/80empty_typeeole_number/errno_27 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80extra_auto_freeze/00-base.xml b/tests/dictionaries/80extra_auto_freeze/00-base.xml new file mode 100644 index 00000000..032f30d3 --- /dev/null +++ b/tests/dictionaries/80extra_auto_freeze/00-base.xml @@ -0,0 +1,15 @@ + + + + + + non + + + + + + diff --git a/tests/dictionaries/80extra_auto_freeze/__init__.py b/tests/dictionaries/80extra_auto_freeze/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80extra_auto_freeze/errno_49 b/tests/dictionaries/80extra_auto_freeze/errno_49 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80extra_auto_freeze/extra_dirs/extra/00-base.xml b/tests/dictionaries/80extra_auto_freeze/extra_dirs/extra/00-base.xml new file mode 100644 index 00000000..7f4f6fe4 --- /dev/null +++ b/tests/dictionaries/80extra_auto_freeze/extra_dirs/extra/00-base.xml @@ -0,0 +1,11 @@ + + + + + + + pre + + + + diff --git a/tests/dictionaries/80family_change/errno_47 b/tests/dictionaries/80family_change/errno_47 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80family_changeaccent/errno_47 b/tests/dictionaries/80family_changeaccent/errno_47 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80family_several/errno_44 b/tests/dictionaries/80family_several/errno_44 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80fill_error/errno_24 b/tests/dictionaries/80fill_error/errno_24 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80fill_multi/errno_24 b/tests/dictionaries/80fill_multi/errno_24 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80hidden_if_in_filelist/errno_10 b/tests/dictionaries/80hidden_if_in_filelist/errno_10 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80leadership_auto_save/errno_29 b/tests/dictionaries/80leadership_auto_save/errno_29 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80leadership_autofreeze/00-base.xml b/tests/dictionaries/80leadership_autofreeze/00-base.xml index 941c98b6..be26dc51 100644 --- a/tests/dictionaries/80leadership_autofreeze/00-base.xml +++ b/tests/dictionaries/80leadership_autofreeze/00-base.xml @@ -2,9 +2,10 @@ - - - + + + + diff --git a/tests/dictionaries/80leadership_autofreeze/errno_30 b/tests/dictionaries/80leadership_autofreeze/errno_30 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80leadership_none_follower_between_follower/errno_33 b/tests/dictionaries/80leadership_none_follower_between_follower/errno_33 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80leadership_not_ordered/errno_33 b/tests/dictionaries/80leadership_not_ordered/errno_33 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80leadership_not_same_family/errno_31 b/tests/dictionaries/80leadership_not_same_family/errno_31 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80leadership_notexists/errno_42 b/tests/dictionaries/80leadership_notexists/errno_42 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80redefine_double_error/errno_48 b/tests/dictionaries/80redefine_double_error/errno_48 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80redefine_error/errno_45 b/tests/dictionaries/80redefine_error/errno_45 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80redefine_fillerror/errno_24 b/tests/dictionaries/80redefine_fillerror/errno_24 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80redefine_notexists/errno_46 b/tests/dictionaries/80redefine_notexists/errno_46 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80separator_multi/errno_35 b/tests/dictionaries/80separator_multi/errno_35 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80separator_multi2/errno_35 b/tests/dictionaries/80separator_multi2/errno_35 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80separator_nonexists/errno_42 b/tests/dictionaries/80separator_nonexists/errno_42 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/80unknown_type/errno_36 b/tests/dictionaries/80unknown_type/errno_36 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/88valid_enum_not_number/errno_13 b/tests/dictionaries/88valid_enum_not_number/errno_13 new file mode 100644 index 00000000..e69de29b diff --git a/tests/dictionaries/88valid_enum_numberdefaultstring/errno_15 b/tests/dictionaries/88valid_enum_numberdefaultstring/errno_15 new file mode 100644 index 00000000..e69de29b diff --git a/tests/test_1_flattener.py b/tests/test_1_flattener.py index 1fe241fe..3d3e8c0c 100644 --- a/tests/test_1_flattener.py +++ b/tests/test_1_flattener.py @@ -71,13 +71,14 @@ def launch_flattener(test_dir, test_ok=False): eolobj.space_visitor(eosfunc) tiramisu_objects = eolobj.save() tiramisu_dir = join(test_dir, 'tiramisu') - tiramisu_file = join(tiramisu_dir, 'base.py') - if not isfile(tiramisu_file) or debug: - with open(tiramisu_file, 'w') as fh: - fh.write(tiramisu_objects) - with open(tiramisu_file, 'r') as fh: - tiramisu_objects_ori = fh.read() - assert tiramisu_objects == tiramisu_objects_ori + if isdir(tiramisu_dir): + tiramisu_file = join(tiramisu_dir, 'base.py') + if not isfile(tiramisu_file) or debug: + with open(tiramisu_file, 'w') as fh: + fh.write(tiramisu_objects) + with open(tiramisu_file, 'r') as fh: + tiramisu_objects_ori = fh.read() + assert tiramisu_objects == tiramisu_objects_ori def fake_traduc(txt): @@ -106,8 +107,15 @@ def test_dictionary(test_dir): def test_error_dictionary(test_dir_error): assert getcwd() == ORI_DIR test_dir = join(dico_dirs, test_dir_error) - with raises(DictConsistencyError): + errno = 0 + for i in listdir(test_dir): + if i.startswith('errno_'): + if errno: + raise Exception('multiple errno') + errno = int(i.split('_')[1]) + with raises(DictConsistencyError) as err: launch_flattener(test_dir) + assert err.value.errno == errno, f'expected errno: {errno}, errno: {err.value.errno}, value: {err.value}' assert getcwd() == ORI_DIR