diff --git a/src/rougail/annotator.py b/src/rougail/annotator.py index d4219777a..907bdefe2 100644 --- a/src/rougail/annotator.py +++ b/src/rougail/annotator.py @@ -50,6 +50,7 @@ def mode_factory(): modes = mode_factory() + # a CreoleObjSpace's attribute has some annotations # that shall not be present in the exported (flatened) XML ERASED_ATTRIBUTES = ('redefine', 'exists', 'fallback', 'optional', 'remove_check', 'namespace', @@ -74,7 +75,7 @@ KEY_TYPE = {'variable': 'symlink', TYPE_PARAM_CHECK = ('string', 'python', 'eole', 'variable') TYPE_PARAM_CONDITION = ('string', 'python', 'number', 'eole', 'variable') -TYPE_PARAM_FILL = ('string', 'eole', 'number', 'context', 'variable') +TYPE_PARAM_FILL = ('string', 'number', 'variable') CONVERSION = {'number': int} ERASED_FAMILY_ACTION_ATTRIBUTES = ('index', 'action') @@ -84,52 +85,73 @@ FREEZE_AUTOFREEZE_VARIABLE = 'module_instancie' class ServiceAnnotator: """Manage service's object + for example:: + + + + 123 + + + """ def __init__(self, objectspace): self.space = objectspace.space self.paths = objectspace.paths self.objectspace = objectspace - """for example:: - - 123 - ntpd - - """ self.grouplist_conditions = {} self.convert_services() def convert_services(self): - if hasattr(self.space, 'services'): - if hasattr(self.space.services, 'service'): - subelts = dict() - for idx, service in enumerate(self.space.services.service.values()): - family = self.objectspace.family() - family.name = 'service{}'.format(idx) - family.doc = service.name - family.family = OrderedDict() - self.convert_service_to_family(family.name, family.family, service) - setattr(self.space.services, family.name, family) - del self.space.services.service - else: - del self.space.services - - def convert_service_to_family(self, service_name, service_family, service): - for elttype, values in vars(service).items(): - if elttype in ['name', 'index', 'method']: - continue + if not hasattr(self.space, 'services'): + return + if not hasattr(self.space.services, 'service'): + del self.space.services + return + for idx, service in enumerate(self.space.services.service.values()): + service_name = f'service{idx}' family = self.objectspace.family() - family.name = elttype + 's' + family.name = service_name + family.doc = service.name + family.mode = None + family.family = self.convert_service_to_family(f'services.{service_name}', + service, + ) + setattr(self.space.services, family.name, family) + del self.space.services.service + + def convert_service_to_family(self, + subpath, + service, + ): + services = {} + for elttype, values in vars(service).items(): + if elttype == 'name' or elttype in ERASED_ATTRIBUTES: + continue + eltname = elttype + 's' + family = self.objectspace.family() + family.name = eltname + family.mode = None if isinstance(values, dict): values = list(values.values()) - family.family = self.convert_subelement_service(elttype, - values, - 'services.{}.{}'.format(service_name, family.name)) - family.mode = None - service_family[family.name] = family + family.family = self.make_group_from_elts(elttype, + values, + f'{subpath}.{eltname}', + ) + services[family.name] = family + return services - def convert_subelement_service(self, name, elts, path): + def make_group_from_elts(self, + name, + elts, + path, + ): + """Splits each objects into a group (and `OptionDescription`, in tiramisu terms) + and build elements and its attributes (the `Options` in tiramisu terms) + """ families = [] - new_elts = self._reorder_elts(name, elts, True) + new_elts = self._reorder_elts(name, + elts, + ) for index, elt_info in enumerate(new_elts): elt = elt_info['elt'] elt_name = elt_info['elt_name'] @@ -151,10 +173,6 @@ class ServiceAnnotator: if key.startswith('_') or key.endswith('_type') or key in ERASED_ATTRIBUTES: continue value = getattr(elt, key) - if isinstance(value, list): - continue - if key == 'service': - value = value.name if key == listname: self.objectspace.list_conditions.setdefault(listname, {}).setdefault( @@ -165,23 +183,27 @@ class ServiceAnnotator: true_key = elt_name else: true_key = key - if true_key in self.objectspace.booleans_attributs: + if key in self.objectspace.booleans_attributs: type_ = 'boolean' else: type_ = 'string' dtd_key_type = true_key + '_type' - if hasattr(elt, dtd_key_type): type_ = KEY_TYPE[getattr(elt, dtd_key_type)] multi = isinstance(value, list) - variables.append(self._generate_element(elt_name, - key, + variables.append(self._generate_element(key, value, type_, subpath, - multi)) + multi, + )) # FIXME ne devrait pas etre True par défaut - variables.append(self._generate_element(name, 'activate', True, 'boolean', subpath)) + # devrait etre un calcule + variables.append(self._generate_element('activate', + True, + 'boolean', + subpath, + )) family = self.objectspace.family() family.name = '{}{}'.format(name, index) family.variable = variables @@ -193,48 +215,39 @@ class ServiceAnnotator: families.append(family) return families - def _generate_element(self, eltname, name, value, type_, subpath, multi=False): - var_data = {'name': name, 'doc': '', 'value': value, - 'auto_freeze': False, 'mode': None, 'multi': multi} - values = None - if type_ == 'string': - values = self.objectspace.forced_choice_option.get(eltname, {}).get(name) - if values is not None: - type_ = 'choice' - var_data['type'] = type_ - + def _generate_element(self, + key, + value, + type_, + subpath, + multi=False, + ): variable = self.objectspace.variable() - variable.mandatory = True - for key, value in var_data.items(): - if key == 'value': - if value is None: - continue - if type_ == 'symlink': - key = 'opt' + variable.name = key + if type_ != 'symlink': + variable.doc = key + variable.multi = multi + variable.mode = None + variable.hidden = True + variable.type = type_ + if value is not None: + if type_ == 'symlink': + variable.opt = value + else: + if not multi: + val = self.objectspace.value() + val.name = value + value = [val] else: - # Value is a list of objects - if not multi: + # value is a list of objects + value_list = [] + for val_iter in value: val = self.objectspace.value() - val.name = value - value = [val] - else: - value_list = [] - for valiter in value: - val = self.objectspace.value() - val.name = valiter.name - value_list.append(val) - value = value_list - if key == 'doc' and type_ == 'symlink': - continue - setattr(variable, key, value) - if values is not None: - choices = [] - for value in values: - choice = self.objectspace.choice() - choice.name = value - choices.append(choice) - variable.choice = choices - path = '{}.{}'.format(subpath, name) + val.name = val_iter.name + value_list.append(val) + value = value_list + variable.value = value + path = f'{subpath}.{key}' self.paths.add_variable('services', path, 'service', @@ -243,10 +256,32 @@ class ServiceAnnotator: ) return variable - def _update_override(self, file_, index, service_path): - self._update_file(file_, index, service_path) + def _reorder_elts(self, + name, + elts, + ): + """Reorders by index the elts + """ + new_elts = {} + # reorder elts by index + for elt in elts: + new_elts.setdefault(elt.index, []).append(elt) + idxes = list(new_elts.keys()) + idxes.sort() + result_elts = [] + for idx in idxes: + for elt in new_elts[idx]: + result_elts.append({'elt_name': name, 'elt': elt}) + return result_elts - def _update_file(self, file_, index, service_path): + def _update_override(self, *args): + self._update_file(*args) + + def _update_file(self, + file_, + index, + service_path, + ): if not hasattr(file_, 'file_type') or file_.file_type == "UnicodeOption": if not hasattr(file_, 'source'): file_.source = basename(file_.name) @@ -254,139 +289,6 @@ class ServiceAnnotator: raise CreoleDictConsistencyError(_('attribute source mandatory for file with variable name ' 'for {}').format(file_.name)) - def _reorder_elts(self, name, elts, duplicate_list): - """Reorders by index the elts - """ - dict_elts = OrderedDict() - # reorder elts by index - new_elts = {} - not_indexed = [] - for elt in elts: - idx = elt.index - new_elts.setdefault(idx, []).append(elt) - idxes = list(new_elts.keys()) - idxes.sort() - elts = not_indexed - for idx in idxes: - elts.extend(new_elts[idx]) - for idx, elt in enumerate(elts): - elt_added = False - for key in dir(elt): - if key.startswith('_') or key.endswith('_type') or key in ERASED_ATTRIBUTES: - continue - value = getattr(elt, key) - if not elt_added: - eltname = elt.name - dict_elts.setdefault(eltname, []).append({'elt_name': name, 'elt': elt}) - - result_elts = [] - for elt in dict_elts.values(): - result_elts.extend(elt) - return result_elts - - def make_group_from_elts(self, name, elts, path, duplicate_list): - """Splits each objects into a group (and `OptionDescription`, in tiramisu terms) - and build elements and its attributes (the `Options` in tiramisu terms) - """ - families = [] - new_elts = self._reorder_elts(name, elts, duplicate_list) - for index, elt_info in enumerate(new_elts): - elt = elt_info['elt'] - elt_name = elt_info['elt_name'] - - # try to launch _update_xxxx() function - update_elt = '_update_' + elt_name - if hasattr(self, update_elt): - getattr(self, update_elt)(elt, index, path) - variables = [] - subpath = '{}.{}{}'.format(path, name, index) - listname = '{}list'.format(name) - activate_path = '.'.join([subpath, 'activate']) - if elt in self.grouplist_conditions: - # FIXME transformer le activate qui disparait en boolean - self.objectspace.list_conditions.setdefault(listname, - {}).setdefault(self.grouplist_conditions[elt], - []).append(activate_path) - for key in dir(elt): - if key.startswith('_') or key.endswith('_type') or key in ERASED_ATTRIBUTES: - continue - value = getattr(elt, key) - if isinstance(value, list) and duplicate_list: - # FIXME plusieurs fichier si calculé ! - continue - if key == listname: - self.objectspace.list_conditions.setdefault(listname, - {}).setdefault( - value, - []).append(activate_path) - continue - if key in self.objectspace.booleans_attributs: - type_ = 'boolean' - else: - type_ = 'string' - dtd_key_type = key + '_type' - if hasattr(elt, dtd_key_type): - type_ = KEY_TYPE[getattr(elt, dtd_key_type)] - multi = isinstance(value, list) - variables.append(self._generate_element(elt_name, - key, - value, - type_, - subpath, - multi)) - # FIXME ne devrait pas etre True par défaut - variables.append(self._generate_element(name, 'activate', True, 'boolean', subpath)) - family = self.objectspace.family() - family.name = '{}{}'.format(name, index) - family.variable = variables - family.mode = None - self.paths.add_family('services', - subpath, - family, - ) - families.append(family) - return families - - -class ActionAnnotator(ServiceAnnotator): - def __init__(self, objectspace): - self.space = objectspace.space - self.paths = objectspace.paths - self.objectspace = objectspace - self.grouplist_conditions = {} - self.convert_family_action() - - def convert_family_action(self): - if hasattr(self.space, 'family_action'): - actions = self.objectspace.family() - actions.name = 'actions' - actions.mode = None - actions.family = [] - self.space.actions = actions - namespaces = [] - for name, actions in self.space.family_action.items(): - subpath = 'actions.{}'.format(normalize_family(name)) - for action in actions.action: - namespace = action.namespace - if namespace in namespaces: - raise CreoleDictConsistencyError(_('only one action allow for {}' - '').format(namespace)) - namespaces.append(namespace) - action.name = action.namespace - new_actions = self.make_group_from_elts('action', actions.action, subpath, False) - family = self.objectspace.family() - family.name = actions.name - family.family = new_actions - family.mode = None - variables = [] - for key, value in vars(actions).items(): - if key not in ERASED_FAMILY_ACTION_ATTRIBUTES: - variables.append(self._generate_element('action', key, value, 'string', - subpath)) - family.variable = variables - self.space.actions.family.append(family) - del self.space.family_action - class SpaceAnnotator(object): """Transformations applied on a CreoleObjSpace instance @@ -415,7 +317,7 @@ class SpaceAnnotator(object): self.filter_condition() self.convert_valid_enums() self.convert_check() - self.convert_autofill() + self.convert_fill() self.remove_empty_families() self.change_variable_mode() self.change_family_mode() @@ -471,6 +373,12 @@ class SpaceAnnotator(object): leader_space.variable = [] leader_space.name = leader_name leader_space.hidden = variable.hidden + if variable.hidden: + leader_is_hidden = True + variable.frozen = True + variable.force_default_on_freeze = True + else: + leader_is_hidden = False variable.hidden = None if hasattr(group, 'description'): leader_space.doc = group.description @@ -490,19 +398,23 @@ class SpaceAnnotator(object): leader_name, ) leader_space.path = leader_fullname - + return leader_is_hidden def manage_follower(self, - namespace: str, - leader_family_name: str, - variable: 'Variable', - leader_name: str, - follower_names: List[str], - leader_space: 'Leadership', - ) -> None: + namespace: str, + leader_family_name: str, + variable: 'Variable', + leader_name: str, + follower_names: List[str], + leader_space: 'Leadership', + leader_is_hidden: bool, + ) -> None: if variable.name != follower_names[0]: raise CreoleDictConsistencyError(_('cannot found this follower {}').format(follower_names[0])) follower_names.remove(variable.name) + if leader_is_hidden: + variable.frozen = True + variable.force_default_on_freeze = True # followers are multi if not variable.multi: raise CreoleDictConsistencyError(_('the variable {} in a group must be multi or submulti').format(variable.name)) @@ -533,12 +445,13 @@ class SpaceAnnotator(object): if has_a_leader: # it's a follower self.manage_follower(namespace, - leader_family_name, - variable, - leader_name, - follower_names, - leader_space, - ) + leader_family_name, + variable, + leader_name, + follower_names, + leader_space, + leader_is_hidden, + ) ori_leader_family.variable.pop(variable.name) if follower_names == []: # no more follower @@ -546,14 +459,14 @@ class SpaceAnnotator(object): elif variable.name == leader_name: # it's a leader leader_space = self.objectspace.Leadership() - self.manage_leader(leader_space, - leader_family_name, - leader_name, - namespace, - variable, - group, - leader_fullname, - ) + leader_is_hidden = self.manage_leader(leader_space, + leader_family_name, + leader_name, + namespace, + variable, + group, + leader_fullname, + ) has_a_leader = True else: raise CreoleDictConsistencyError(_('cannot found followers {}').format(follower_names)) @@ -611,7 +524,7 @@ class SpaceAnnotator(object): variable.mode = modes_level[0] # if the variable is mandatory and doesn't have any value # then the variable's mode is set to 'basic' - has_value = hasattr(variable, 'value') + has_value = hasattr(variable, 'value') and variable.value != None if (path not in self.has_calc and variable.mandatory is True and (not has_value or is_follower) and variable.type != 'choice'): variable.mode = modes_level[0] @@ -793,81 +706,64 @@ class SpaceAnnotator(object): path = '{}.{}'.format(family.path, variable.name) self._annotate_variable(variable, family_mode, path) - def get_variable(self, name): # pylint: disable=C0111 - return self.paths.get_variable_obj(name) - - def convert_autofill(self): # pylint: disable=C0111 - if hasattr(self.space, 'constraints'): - self.convert_duplicate_autofill(self.space.constraints) - if 'auto' in vars(self.space.constraints): - self.convert_auto(self.space.constraints.auto, self.space) - if 'fill' in vars(self.space.constraints): - self.convert_fill(self.space.constraints.fill, self.space) - - def convert_duplicate_autofill(self, constraints): - """ Remove duplicate auto or fill for a variable - This variable must be redefined - """ - fills = {} + def convert_fill(self): # pylint: disable=C0111,R0912 + if not hasattr(self.space, 'constraints') or not hasattr(self.space.constraints, 'fill'): + return # sort fill/auto by index - if 'fill' in vars(constraints): - for idx, fill in enumerate(constraints.fill): - fills[fill.index] = {'idx': idx, 'fill': fill, 'type': 'fill'} - if 'auto' in vars(constraints): - for idx, fill in enumerate(constraints.auto): - fills[fill.index] = {'idx': idx, 'fill': fill, 'type': 'auto'} + fills = {fill.index: fill for idx, fill in enumerate(self.space.constraints.fill)} indexes = list(fills.keys()) indexes.sort() - targets = {} - remove_autos = [] - remove_fills = [] + targets = [] + eosfunc = dir(self.eosfunc) for idx in indexes: - fill = fills[idx]['fill'] - redefine = bool(fill.redefine) - if fill.target in targets: - if redefine: - if targets[fill.target][1] == 'auto': - remove_autos.append(targets[fill.target][0]) - else: - remove_fills.append(targets[fill.target][0]) - else: - raise CreoleDictConsistencyError(_("An auto or fill already exists " - "for the target: {}").format( - fill.target)) - targets[fill.target] = (fills[idx]['idx'], fills[idx]['type']) - remove_autos.sort(reverse=True) - for idx in remove_autos: - constraints.auto.pop(idx) - remove_fills.sort(reverse=True) - for idx in remove_fills: - constraints.fill.pop(idx) + fill = fills[idx] + # test if it's redefined calculation + if fill.target in targets and not fill.redefine: + raise CreoleDictConsistencyError(_(f"A fill already exists for the target: {fill.target}")) + targets.append(fill.target) + # + if not fill.name in eosfunc: + raise CreoleDictConsistencyError(_('cannot find fill function {}').format(fill.name)) - def convert_auto(self, auto_space, space): # pylint: disable=C0111 - for auto in auto_space: - if HIGH_COMPATIBILITY and auto.target in self.has_frozen_if_in_condition: - # if a variable has a 'frozen_if_in' condition - # then we change the 'auto' variable as a 'fill' variable - continue - # an auto is a fill with "hidden" and "frozen" properties - variable = self.get_variable(auto.target) - if variable.auto_freeze: - raise CreoleDictConsistencyError(_('variable with auto value ' - 'cannot be auto_freeze').format(auto.target)) - if variable.auto_save: - raise CreoleDictConsistencyError(_('variable with auto value ' - 'cannot be auto_save').format(auto.target)) - leader = self.paths.get_leader(auto.target) - if leader is None or variable.name != leader: - variable.hidden = True - else: - leadership = self.paths.get_family_obj(self.paths.get_variable_family_path(auto.target)) - leadership.hidden = True - variable.frozen = True - variable.force_default_on_freeze = True - if 'fill' not in vars(space.constraints): - space.constraints.fill = [] - space.constraints.fill.extend(auto_space) - del space.constraints.auto + namespace = fill.namespace + # let's replace the target by the path + fill.target = self.paths.get_variable_path(fill.target, + namespace) + + value = self.objectspace.value() + value.type = 'calculation' + value.name = fill.name + if hasattr(fill, 'param'): + param_to_delete = [] + for fill_idx, param in enumerate(fill.param): + if param.type not in TYPE_PARAM_FILL: + raise CreoleDictConsistencyError(_(f'cannot use {param.type} type as a param in a fill/auto')) + if param.type != 'string' and not hasattr(param, 'text'): + raise CreoleDictConsistencyError(_(f"All '{param.type}' variables shall have a value in order to calculate {fill.target}")) + if param.type == 'variable': + try: + param.text, suffix = self.paths.get_variable_path(param.text, + namespace, + with_suffix=True) + if suffix: + param.suffix = suffix + except CreoleDictConsistencyError as err: + if param.optional is False: + raise err + param_to_delete.append(fill_idx) + continue + if param.hidden is True: + param.transitive = False + param.hidden = None + param_to_delete.sort(reverse=True) + for param_idx in param_to_delete: + fill.param.pop(param_idx) + value.param = fill.param + variable = self.paths.get_variable_obj(fill.target) + variable.value = [value] + self.force_not_mandatory.append(fill.target) + self.has_calc.append(fill.target) + del self.space.constraints.fill def filter_separators(self): # pylint: disable=C0111,R0201 # FIXME devrait etre dans la variable @@ -991,7 +887,7 @@ class SpaceAnnotator(object): for param_idx, param in enumerate(check.param): if hasattr(param, 'name') and param.name == 'checkval': try: - proposed_value_type = self.objectspace._convert_boolean(param.text) == False + proposed_value_type = self.objectspace.convert_boolean(param.text) == False remove_params.append(param_idx) except TypeError as err: raise CreoleDictConsistencyError(_('cannot load checkval value for variable {}: {}').format(check.target, err)) @@ -1080,97 +976,6 @@ class SpaceAnnotator(object): variable.check.append(check_) del self.space.constraints.check - - def convert_fill(self, fill_space, space): # pylint: disable=C0111,R0912 - fills = {} - # sort fill/auto by index - for idx, fill in enumerate(fill_space): - fills[fill.index] = {'idx': idx, 'fill': fill} - del fill.index - indexes = list(fills.keys()) - indexes.sort() - del_idx = [] - for idx in indexes: - fill = fills[idx]['fill'] - variable = self.get_variable(fill.target) - if hasattr(variable, 'value'): - del variable.value - namespace = fill.namespace - # let's replace the target by the path - fill.target = self.paths.get_variable_path(fill.target, namespace) - if not fill.name in dir(self.eosfunc): - raise CreoleDictConsistencyError(_('cannot find fill function {}').format(fill.name)) - #is_probe = not fill.name in self.eosfunc.func_on_zephir_context - if hasattr(fill, 'param'): - for param in fill.param: - if param.type not in TYPE_PARAM_FILL: - raise CreoleDictConsistencyError(_('cannot use {} type as a param ' - 'in a fill/auto').format(param.type)) - if param.type == 'eole': - param.type = 'variable' - param_option_indexes = [] - for fill_idx, param in enumerate(fill.param): - if not hasattr(param, 'text') and \ - (param.type == 'variable' or param.type == 'number' or \ - param.type == 'python'): - raise CreoleDictConsistencyError(_("All '{}' variables shall be set in " - "order to calculate {}").format( - param.type, - fill.target)) - # if param.type == 'container': - # param.type = 'eole' - # param.text = 'container_ip_{}'.format(param.text) - if param.type == 'variable': - #if is_probe: - # raise CreoleDictConsistencyError(_('Function {0} used to calculate {1} ' - # 'is executed on remote server, ' - # 'so cannot depends to an ' - # 'other variable' - # ).format(fill.name, fill.target)) - # if HIGH_COMPATIBILITY and param.text.startswith('container_ip'): - # if param.optional is True: - # param_option_indexes.append(fill_idx) - try: - param.text, suffix = self.paths.get_variable_path(param.text, - namespace, - with_suffix=True) - if suffix: - param.suffix = suffix - except CreoleDictConsistencyError as err: - if param.optional is True: - param_option_indexes.append(fill_idx) - else: - raise err - param_option_indexes = list(set(param_option_indexes)) - param_option_indexes.sort(reverse=True) - for param_idx in param_option_indexes: - fill.param.pop(param_idx) - self.has_calc.append(fill.target) - - #if is_probe: - # variable.force_default_on_freeze = False - # self.objectspace.probe_variables.append(fill) - # del_idx.append(fills[idx]['idx']) - del_idx.sort(reverse=True) - for idx in del_idx: - space.constraints.fill.pop(idx) - for fill in space.constraints.fill: - variable = self.paths.get_variable_obj(fill.target) - value = self.objectspace.value() - value.type = 'calculation' - value.name = fill.name - if hasattr(fill, 'param'): - for param in fill.param: - if param.hidden is True: - param.transitive = False - param.hidden = None - value.param = fill.param - if not hasattr(variable, 'value'): - variable.value = [] - variable.value.append(value) - self.force_not_mandatory.append(fill.target) - del space.constraints.fill - def filter_targets(self): # pylint: disable=C0111 for condition_idx, condition in enumerate(self.space.constraints.condition): namespace = condition.namespace @@ -1228,15 +1033,14 @@ class SpaceAnnotator(object): if target.type in ['variable', 'family']: name = target.name.split('.')[-1] if target.type == 'variable': - variable = self.get_variable(name) + variable = self.paths.get_variable_obj(name) else: variable = self.paths.get_family_obj(name) if condition.name in ['disabled_if_in']: variable.disabled = True if condition.name in ['mandatory_if_in']: variable.mandatory = True - if condition.name in ['disabled_if_in', 'disabled_if_not_in', - 'frozen_if_in', 'frozen_if_not_in']: + if condition.name in ['frozen_if_in', 'frozen_if_not_in']: variable.hidden = False if HIGH_COMPATIBILITY: fallback_variables.append(name) @@ -1249,15 +1053,14 @@ class SpaceAnnotator(object): if listvars: for listvar in listvars: try: - variable = self.get_variable(listvar) + variable = self.paths.get_variable_obj(listvar) except CreoleDictConsistencyError: variable = self.paths.get_family_obj(listvar) if condition.name in ['disabled_if_in']: variable.disabled = True if condition.name in ['mandatory_if_in']: variable.mandatory = True - if condition.name in ['disabled_if_in', 'disabled_if_not_in', - 'frozen_if_in', 'frozen_if_not_in']: + if condition.name in ['frozen_if_in', 'frozen_if_not_in']: variable.hidden = False fallback_lists.append(listvar) remove_conditions.append(idx) @@ -1283,7 +1086,7 @@ class SpaceAnnotator(object): if listvar in fallback_lists: continue try: - variable = self.get_variable(listvar) + variable = self.paths.get_variable_obj(listvar) type_ = 'variable' except CreoleDictConsistencyError: variable = self.paths.get_family_obj(listvar) @@ -1347,7 +1150,7 @@ class SpaceAnnotator(object): else: name = target.name if target.type == 'variable': - variable = self.get_variable(name) + variable = self.paths.get_variable_obj(name) else: variable = self.paths.get_family_obj(name) if condition.name == 'disabled_if_not_in': @@ -1362,8 +1165,6 @@ class SpaceAnnotator(object): variable.mandatory = True force_remove_targets.setdefault(condition.name, []).append(target.name) - elif HIGH_COMPATIBILITY and condition.name == 'disabled_if_in': - variable.hidden = False remove_conditions.append(condition_idx) remove_conditions = list(set(remove_conditions)) remove_conditions.sort(reverse=True) @@ -1382,14 +1183,13 @@ class SpaceAnnotator(object): else: name = target.name if target.type == 'variable': - variable = self.get_variable(name) + variable = self.paths.get_variable_obj(name) else: variable = self.paths.get_family_obj(name) if name in fallback_variables: remove_targets.append(target_idx) continue - if condition.name in ['disabled_if_in', 'disabled_if_not_in', - 'frozen_if_in', 'frozen_if_not_in']: + if condition.name in ['frozen_if_in', 'frozen_if_not_in']: variable.hidden = False if condition.name in ['mandatory_if_in', 'mandatory_if_not_in']: variable.mandatory = False @@ -1463,7 +1263,7 @@ class SpaceAnnotator(object): else: name = target.name if target.type == 'variable': - variable = self.get_variable(name) + variable = self.paths.get_variable_obj(name) else: variable = self.paths.get_family_obj(name) if not hasattr(variable, 'property'): diff --git a/src/rougail/data/rougail.dtd b/src/rougail/data/rougail.dtd index 555c7397a..778a84eca 100644 --- a/src/rougail/data/rougail.dtd +++ b/src/rougail/data/rougail.dtd @@ -37,17 +37,12 @@ - + - - - - - @@ -81,10 +76,6 @@ - - - - @@ -93,9 +84,6 @@ - - - @@ -106,8 +94,6 @@ - - @@ -158,7 +144,7 @@ - + @@ -168,10 +154,6 @@ - - - - diff --git a/src/rougail/objspace.py b/src/rougail/objspace.py index 4654e3b76..93f7c152c 100644 --- a/src/rougail/objspace.py +++ b/src/rougail/objspace.py @@ -25,17 +25,16 @@ has to be moved in family2. The visit procedure changes the varable1's object sp """ from collections import OrderedDict from lxml.etree import Element, SubElement # pylint: disable=E0611 -from json import dump - from .i18n import _ from .xmlreflector import XMLReflector, HIGH_COMPATIBILITY -from .annotator import ERASED_ATTRIBUTES, ActionAnnotator, ServiceAnnotator, SpaceAnnotator +from .annotator import ERASED_ATTRIBUTES, ServiceAnnotator, SpaceAnnotator from .utils import normalize_family from .error import CreoleOperationError, SpaceObjShallNotBeUpdated, CreoleDictConsistencyError +from .path import Path # CreoleObjSpace's elements like 'family' or 'follower', that shall be forced to the Redefinable type -FORCE_REDEFINABLES = ('family', 'follower', 'service', 'disknod', 'variables', 'family_action') +FORCE_REDEFINABLES = ('family', 'follower', 'service', 'disknod', 'variables') # CreoleObjSpace's elements that shall be forced to the UnRedefinable type FORCE_UNREDEFINABLES = ('value', 'input', 'profile', 'ewtapp', 'tag', 'saltaction') # CreoleObjSpace's elements that shall be set to the UnRedefinable type @@ -48,16 +47,17 @@ CONVERT_PROPERTIES = {'auto_save': ['force_store_value'], 'auto_freeze': ['force RENAME_ATTIBUTES = {'description': 'doc'} INCOMPATIBLE_ATTRIBUTES = [['multi', 'submulti']] +FORCED_TEXT_ELTS_AS_NAME = ('choice', 'property') #TYPE_TARGET_CONDITION = ('variable', 'family') # _____________________________________________________________________________ # special types definitions for the Object Space's internal representation -class RootCreoleObject(object): +class RootCreoleObject: "" -class CreoleObjSpace(object): +class CreoleObjSpace: """DOM XML reflexion free internal representation of a Creole Dictionary """ choice = type('Choice', (RootCreoleObject,), OrderedDict()) @@ -78,80 +78,258 @@ class CreoleObjSpace(object): def __init__(self, dtdfilename): # pylint: disable=R0912 self.index = 0 - class ObjSpace(object): # pylint: disable=R0903 + class ObjSpace: # pylint: disable=R0903 """ Base object space """ self.space = ObjSpace() + self.paths = Path() self.xmlreflector = XMLReflector() self.xmlreflector.parse_dtd(dtdfilename) self.redefine_variables = None - self.probe_variables = [] # ['variable', 'separator', 'family'] self.forced_text_elts = set() - self.forced_text_elts_as_name = set(['choice', 'property']) - self.forced_choice_option = {} - self.paths = Path() + self.forced_text_elts_as_name = set(FORCED_TEXT_ELTS_AS_NAME) self.list_conditions = {} - self.booleans_attributs = [] - for elt in self.xmlreflector.dtd.iterelements(): - attrs = {} - clstype = self.UnRedefinable - atomic = True - forced_text_elt = False - if elt.type == 'mixed': - forced_text_elt = True - if elt.name == 'service': - self.parse_dtd_right_left_elt(elt.content) - for attr in elt.iterattributes(): - atomic = False - if attr.default_value: - if attr.default_value == 'True': - default_value = True - elif attr.default_value == 'False': - default_value = False - else: - default_value = attr.default_value - attrs[attr.name] = default_value - if not attr.name.endswith('_type'): - values = list(attr.itervalues()) - if values != []: - self.forced_choice_option.setdefault(elt.name, {})[attr.name] = values + self.make_object_space_class() - if attr.name == 'redefine': + def make_object_space_class(self): + """Create Rougail ObjectSpace class types, it enables us to create objects like: + File(), Variable(), Ip(), Family(), Constraints()... and so on. + + Creole ObjectSpace is an object's reflexion of the XML elements""" + + for dtd_elt in self.xmlreflector.dtd.iterelements(): + attrs = {} + if dtd_elt.name in FORCE_REDEFINABLES: + clstype = self.Redefinable + else: + clstype = self.UnRedefinable + atomic = dtd_elt.name not in FORCE_UNREDEFINABLES and dtd_elt.name not in FORCE_REDEFINABLES + forced_text_elt = dtd_elt.type == 'mixed' + for dtd_attr in dtd_elt.iterattributes(): + atomic = False + if set(dtd_attr.itervalues()) == set(['True', 'False']): + # it's a boolean + self.booleans_attributs.append(dtd_attr.name) + if dtd_attr.default_value: + # set default value for this attribute + default_value = dtd_attr.default_value + if dtd_attr.name in self.booleans_attributs: + default_value = self.convert_boolean(dtd_attr.default_value) + attrs[dtd_attr.name] = default_value + if dtd_attr.name == 'redefine': + # has a redefine attribute, so it's a Redefinable object clstype = self.Redefinable - if attr.name == 'name' and forced_text_elt is True: - self.forced_text_elts.add(elt.name) + if dtd_attr.name == 'name' and forced_text_elt: + # child.text should be transform has a "name" attribute + self.forced_text_elts.add(dtd_elt.name) forced_text_elt = False - if set(attr.itervalues()) == set(['True', 'False']): - self.booleans_attributs.append(attr.name) - if forced_text_elt is True: - self.forced_text_elts_as_name.add(elt.name) - - if elt.name in FORCE_REDEFINABLES: - clstype = self.Redefinable - elif elt.name in FORCE_UNREDEFINABLES: - clstype = self.UnRedefinable - elif atomic: + self.forced_text_elts_as_name.add(dtd_elt.name) + if atomic: + # has any attribute so it's an Atomic object clstype = self.Atom - # Creole ObjectSpace class types, it enables us to create objects like: - # Service_restriction(), Ip(), Interface(), Host(), Fstab(), Package(), Disknod(), - # File(), Variables(), Family(), Variable(), Separators(), Separator(), Value(), - # Constraints()... and so on. Creole ObjectSpace is an object's reflexion of - # the XML elements - setattr(self, elt.name, type(elt.name.capitalize(), (clstype,), attrs)) + # create ObjectSpace object + setattr(self, dtd_elt.name, type(dtd_elt.name.capitalize(), (clstype,), attrs)) - def parse_dtd_right_left_elt(self, elt): - if elt.right.type == 'or': - self.parse_dtd_right_left_elt(elt.right) + def create_or_populate_from_xml(self, + namespace, + xmlfolders): + """Parses a bunch of XML files + populates the CreoleObjSpace + """ + for xmlfile, document in self.xmlreflector.load_xml_from_folders(xmlfolders): + self.redefine_variables = [] + self.xml_parse_document(document, + self.space, + namespace, + ) - def _convert_boolean(self, value): # pylint: disable=R0201 + def xml_parse_document(self, + document, + space, + namespace, + ): + """Parses a Creole XML file + populates the CreoleObjSpace + """ + family_names = [] + for child in document: + # this index enables us to reorder objects + self.index += 1 + # doesn't proceed the XML commentaries + if not isinstance(child.tag, str): + continue + if child.tag == 'family': + if child.attrib['name'] in family_names: + raise CreoleDictConsistencyError(_('Family {} is set several times').format(child.attrib['name'])) + family_names.append(child.attrib['name']) + if child.tag == 'variables': + child.attrib['name'] = namespace + if HIGH_COMPATIBILITY and child.tag == 'value' and child.text == None: + # FIXME should not be here + continue + # creole objects creation + try: + creoleobj = self.generate_creoleobj(child, + space, + namespace, + ) + except SpaceObjShallNotBeUpdated: + continue + self.set_text_to_obj(child, + creoleobj, + ) + self.set_xml_attributes_to_obj(child, + creoleobj, + ) + self.creoleobj_tree_visitor(child, + creoleobj, + namespace, + ) + self.fill_creoleobj_path_attribute(space, + child, + namespace, + document, + creoleobj, + ) + self.add_to_tree_structure(creoleobj, + space, + child, + ) + if list(child) != []: + self.xml_parse_document(child, + creoleobj, + namespace, + ) + + def generate_creoleobj(self, + child, + space, + namespace, + ): + """ + instanciates or creates Creole Object Subspace objects + """ + creoleobj = getattr(self, child.tag)() + if isinstance(creoleobj, self.Redefinable): + creoleobj = self.create_or_update_redefinable_object(child.attrib, + space, + child, + namespace, + ) + elif isinstance(creoleobj, self.Atom) and child.tag in vars(space): + # instanciates an object from the CreoleObjSpace's builtins types + # example : child.tag = constraints -> a self.Constraints() object is created + # this Atom instance has to be a singleton here + # we do not re-create it, we reuse it + creoleobj = getattr(space, child.tag) + self.create_tree_structure(space, + child, + creoleobj, + ) + return creoleobj + + def create_or_update_redefinable_object(self, + subspace, + space, + child, + namespace, + ): + """Creates or retrieves the space object that corresponds + to the `child` XML object + + Two attributes of the `child` XML object are important: + + - with the `redefine` boolean flag attribute we know whether + the corresponding space object shall be created or updated + + - `True` means that the corresponding space object shall be updated + - `False` means that the corresponding space object shall be created + + - with the `exists` boolean flag attribute we know whether + the corresponding space object shall be created + (or nothing -- that is the space object isn't modified) + + - `True` means that the corresponding space object shall be created + - `False` means that the corresponding space object is not updated + + In the special case `redefine` is True and `exists` is False, + we create the corresponding space object if it doesn't exist + and we update it if it exists. + + :return: the corresponding space object of the `child` XML object + """ + if child.tag in self.forced_text_elts_as_name: + name = child.text + else: + name = subspace['name'] + if self.is_already_exists(name, + space, + child, + namespace, + ): + default_redefine = child.tag in FORCE_REDEFINABLES + redefine = self.convert_boolean(subspace.get('redefine', default_redefine)) + exists = self.convert_boolean(subspace.get('exists', True)) + if redefine is True: + return self.translate_in_space(name, + space, + child, + namespace, + ) + elif exists is False: + raise SpaceObjShallNotBeUpdated() + raise CreoleDictConsistencyError(_(f'Already present in another XML file, {name} cannot be re-created')) + redefine = self.convert_boolean(subspace.get('redefine', False)) + exists = self.convert_boolean(subspace.get('exists', False)) + if redefine is False or exists is True: + return getattr(self, child.tag)() + raise CreoleDictConsistencyError(_(f'Redefined object: {name} does not exist yet')) + + def create_tree_structure(self, + space, + child, + creoleobj, + ): # pylint: disable=R0201 + """ + Builds the tree structure of the object space here + we set services attributes in order to be populated later on + for example:: + + space = Family() + space.variable = OrderedDict() + another example: + space = Variable() + space.value = list() + """ + if child.tag not in vars(space): + if isinstance(creoleobj, self.Redefinable): + setattr(space, child.tag, OrderedDict()) + elif isinstance(creoleobj, self.UnRedefinable): + setattr(space, child.tag, []) + elif not isinstance(creoleobj, self.Atom): # pragma: no cover + raise CreoleOperationError(_("Creole object {} " + "has a wrong type").format(type(creoleobj))) + + def is_already_exists(self, name, space, child, namespace): + if isinstance(space, self.family): # pylint: disable=E1101 + if namespace != 'creole': + name = space.path + '.' + name + return self.paths.path_is_defined(name) + if child.tag == 'family': + norm_name = normalize_family(name) + else: + norm_name = name + return norm_name in getattr(space, child.tag, {}) + + def convert_boolean(self, value): # pylint: disable=R0201 """Boolean coercion. The Creole XML may contain srings like `True` or `False` """ if isinstance(value, bool): @@ -163,20 +341,14 @@ class CreoleObjSpace(object): else: raise TypeError(_('{} is not True or False').format(value)) # pragma: no cover - def _is_already_exists(self, name, space, child, namespace): - if isinstance(space, self.family): # pylint: disable=E1101 - if namespace != 'creole': - name = space.path + '.' + name - return self.paths.path_is_defined(name) - if child.tag in ['family', 'family_action']: - norm_name = normalize_family(name) - else: - norm_name = name - return norm_name in getattr(space, child.tag, {}) - - def _translate_in_space(self, name, family, variable, namespace): + def translate_in_space(self, + name, + family, + variable, + namespace, + ): if not isinstance(family, self.family): # pylint: disable=E1101 - if variable.tag in ['family', 'family_action']: + if variable.tag == 'family': norm_name = normalize_family(name) else: norm_name = name @@ -213,6 +385,7 @@ class CreoleObjSpace(object): remove_checks.sort(reverse=True) for idx in remove_checks: self.space.constraints.check.pop(idx) # pylint: disable=E1101 + def remove_condition(self, name): # pylint: disable=C0111 for idx, condition in enumerate(self.space.constraints.condition): # pylint: disable=E1101 remove_targets = [] @@ -225,101 +398,14 @@ class CreoleObjSpace(object): for idx in remove_targets: del condition.target[idx] - def create_or_update_space_object(self, subspace, space, child, namespace): - """Creates or retrieves the space object that corresponds - to the `child` XML object - - Two attributes of the `child` XML object are important: - - - with the `redefine` boolean flag attribute we know whether - the corresponding space object shall be created or updated - - - `True` means that the corresponding space object shall be updated - - `False` means that the corresponding space object shall be created - - - with the `exists` boolean flag attribute we know whether - the corresponding space object shall be created - (or nothing -- that is the space object isn't modified) - - - `True` means that the corresponding space object shall be created - - `False` means that the corresponding space object is not updated - - In the special case `redefine` is True and `exists` is False, - we create the corresponding space object if it doesn't exist - and we update it if it exists. - - :return: the corresponding space object of the `child` XML object - """ - if child.tag in self.forced_text_elts_as_name: - name = child.text - else: - name = subspace['name'] - if self._is_already_exists(name, space, child, namespace): - if child.tag in FORCE_REDEFINABLES: - redefine = self._convert_boolean(subspace.get('redefine', True)) - else: - redefine = self._convert_boolean(subspace.get('redefine', False)) - exists = self._convert_boolean(subspace.get('exists', True)) - if redefine is True: - return self._translate_in_space(name, space, child, namespace) - elif exists is False: - raise SpaceObjShallNotBeUpdated() - else: - raise CreoleDictConsistencyError(_('Already present in another XML file, {} ' - 'cannot be re-created').format(name)) - else: - redefine = self._convert_boolean(subspace.get('redefine', False)) - exists = self._convert_boolean(subspace.get('exists', False)) - if redefine is False or exists is True: - return getattr(self, child.tag)() - else: - raise CreoleDictConsistencyError(_('Redefined object: ' - '{} does not exist yet').format(name)) - - def generate_creoleobj(self, child, space, namespace): - """ - instanciates or creates Creole Object Subspace objects - """ - if issubclass(getattr(self, child.tag), self.Redefinable): - creoleobj = self.create_or_update_space_object(child.attrib, space, child, namespace) - else: - # instanciates an object from the CreoleObjSpace's builtins types - # example : child.tag = constraints -> a self.Constraints() object is created - creoleobj = getattr(self, child.tag)() - # this Atom instance has to be a singleton here - # we do not re-create it, we reuse it - if isinstance(creoleobj, self.Atom) and child.tag in vars(space): - creoleobj = getattr(space, child.tag) - self.create_tree_structure(space, child, creoleobj) - return creoleobj - - def create_tree_structure(self, space, child, creoleobj): # pylint: disable=R0201 - """ - Builds the tree structure of the object space here - we set services attributes in order to be populated later on - for example:: - - space = Family() - space.variable = OrderedDict() - another example: - space = Variable() - space.value = list() - """ - if child.tag not in vars(space): - if isinstance(creoleobj, self.Redefinable): - setattr(space, child.tag, OrderedDict()) - elif isinstance(creoleobj, self.UnRedefinable): - setattr(space, child.tag, []) - elif isinstance(creoleobj, self.Atom): - pass - else: # pragma: no cover - raise CreoleOperationError(_("Creole object {} " - "has a wrong type").format(type(creoleobj))) - - def _add_to_tree_structure(self, creoleobj, space, child): # pylint: disable=R0201 + def add_to_tree_structure(self, + creoleobj, + space, + child, + ): # pylint: disable=R0201 if isinstance(creoleobj, self.Redefinable): name = creoleobj.name - if child.tag == 'family' or child.tag == 'family_action': + if child.tag == 'family': name = normalize_family(name) getattr(space, child.tag)[name] = creoleobj elif isinstance(creoleobj, self.UnRedefinable): @@ -327,7 +413,10 @@ class CreoleObjSpace(object): else: setattr(space, child.tag, creoleobj) - def _set_text_to_obj(self, child, creoleobj): + def set_text_to_obj(self, + child, + creoleobj, + ): if child.text is None: text = None else: @@ -338,28 +427,24 @@ class CreoleObjSpace(object): else: creoleobj.text = text - def _set_xml_attributes_to_obj(self, child, creoleobj): - redefine = self._convert_boolean(child.attrib.get('redefine', False)) + def set_xml_attributes_to_obj(self, + child, + creoleobj, + ): + redefine = self.convert_boolean(child.attrib.get('redefine', False)) has_value = hasattr(creoleobj, 'value') if HIGH_COMPATIBILITY and has_value: has_value = len(child) != 1 or child[0].text != None - if (redefine is True and child.tag == 'variable' and has_value - and len(child) != 0): + if redefine is True and child.tag == 'variable' and has_value and len(child) != 0: del creoleobj.value for attr, val in child.attrib.items(): if redefine and attr in UNREDEFINABLE: # UNREDEFINABLE concerns only 'variable' node so we can fix name # to child.attrib['name'] name = child.attrib['name'] - raise CreoleDictConsistencyError(_("cannot redefine attribute {} for variable {}").format(attr, name)) - if isinstance(getattr(creoleobj, attr, None), bool): - if val == 'False': - val = False - elif val == 'True': - val = True - else: # pragma: no cover - raise CreoleOperationError(_('value for {} must be True or False, ' - 'not {}').format(attr, val)) + raise CreoleDictConsistencyError(_(f'cannot redefine attribute {attr} for variable {name}')) + if attr in self.booleans_attributs: + val = self.convert_boolean(val) if not (attr == 'name' and getattr(creoleobj, 'name', None) != None): setattr(creoleobj, attr, val) keys = list(vars(creoleobj).keys()) @@ -371,113 +456,63 @@ class CreoleObjSpace(object): raise CreoleDictConsistencyError(_('those attributes are incompatible {}').format(incompatible)) found = True - - def _creoleobj_tree_visitor(self, child, creoleobj, namespace): + def creoleobj_tree_visitor(self, + child, + creoleobj, + namespace, + ): """Creole object tree manipulations """ - if child.tag == 'variable' and child.attrib.get('remove_check', False): - self.remove_check(creoleobj.name) - if child.tag == 'variable' and child.attrib.get('remove_condition', False): - self.remove_condition(creoleobj.name) - if child.tag in ['auto', 'fill', 'check']: - variable_name = child.attrib['target'] + if child.tag == 'variable': + if child.attrib.get('remove_check', False): + self.remove_check(creoleobj.name) + if child.attrib.get('remove_condition', False): + self.remove_condition(creoleobj.name) + if child.tag in ['fill', 'check']: + # if variable is a redefine in current dictionary # XXX not working with variable not in creole and in leader/followers - if variable_name in self.redefine_variables: - creoleobj.redefine = True - else: - creoleobj.redefine = False + creoleobj.redefine = child.attrib['target'] in self.redefine_variables if not hasattr(creoleobj, 'index'): creoleobj.index = self.index - if child.tag in ['auto', 'fill', 'condition', 'check', 'action']: + if child.tag in ['fill', 'condition', 'check', 'action']: creoleobj.namespace = namespace - def xml_parse_document(self, document, space, namespace, is_in_family=False): - """Parses a Creole XML file - populates the CreoleObjSpace - """ - family_names = [] - for child in document: - # this index enables us to reorder the 'fill' and 'auto' objects - self.index += 1 - # doesn't proceed the XML commentaries - if not isinstance(child.tag, str): - continue - if child.tag == 'family': - is_in_family = True - if child.attrib['name'] in family_names: - raise CreoleDictConsistencyError(_('Family {} is set several times').format(child.attrib['name'])) - family_names.append(child.attrib['name']) - if child.tag == 'variables': - child.attrib['name'] = namespace - if HIGH_COMPATIBILITY and child.tag == 'value' and child.text == None: - continue - # creole objects creation - try: - creoleobj = self.generate_creoleobj(child, space, namespace) - except SpaceObjShallNotBeUpdated: - continue - self._set_text_to_obj(child, creoleobj) - self._set_xml_attributes_to_obj(child, creoleobj) - self._creoleobj_tree_visitor(child, creoleobj, namespace) - self._fill_creoleobj_path_attribute(space, child, namespace, document, creoleobj) - self._add_to_tree_structure(creoleobj, space, child) - if list(child) != []: - self.xml_parse_document(child, creoleobj, namespace, is_in_family) - - def _fill_creoleobj_path_attribute(self, - space, - child, - namespace, - document, - creoleobj, - ): # pylint: disable=R0913 + def fill_creoleobj_path_attribute(self, + space, + child, + namespace, + document, + creoleobj, + ): # pylint: disable=R0913 """Fill self.paths attributes """ - if not isinstance(space, self.help): # pylint: disable=E1101 - if child.tag == 'variable': - family_name = normalize_family(document.attrib['name']) - self.paths.add_variable(namespace, - child.attrib['name'], - family_name, - document.attrib.get('dynamic') != None, - creoleobj) - if child.attrib.get('redefine', 'False') == 'True': - if namespace == 'creole': - self.redefine_variables.append(child.attrib['name']) - else: - self.redefine_variables.append(namespace + '.' + family_name + '.' + - child.attrib['name']) + if isinstance(space, self.help): # pylint: disable=E1101 + return + if child.tag == 'variable': + family_name = normalize_family(document.attrib['name']) + self.paths.add_variable(namespace, + child.attrib['name'], + family_name, + document.attrib.get('dynamic') != None, + creoleobj) + if child.attrib.get('redefine', 'False') == 'True': + if namespace == 'creole': + self.redefine_variables.append(child.attrib['name']) + else: + self.redefine_variables.append(namespace + '.' + family_name + '.' + + child.attrib['name']) - if child.tag == 'family': - family_name = normalize_family(child.attrib['name']) - if namespace != 'creole': - family_name = namespace + '.' + family_name - self.paths.add_family(namespace, - family_name, - creoleobj, - ) - creoleobj.path = self.paths.get_family_path(family_name, namespace) - - def create_or_populate_from_xml(self, namespace, xmlfolders, from_zephir=None): - """Parses a bunch of XML files - populates the CreoleObjSpace - """ - documents = self.xmlreflector.load_xml_from_folders(xmlfolders, from_zephir) - for xmlfile, document in documents: - try: - self.redefine_variables = [] - self.xml_parse_document(document, self.space, namespace) - except Exception as err: - #print(_('error in XML file {}').format(xmlfile)) - raise err - - def populate_from_zephir(self, namespace, xmlfile): - self.redefine_variables = [] - document = self.xmlreflector.parse_xmlfile(xmlfile, from_zephir=True, zephir2=True) - self.xml_parse_document(document, self.space, namespace) + elif child.tag == 'family': + family_name = normalize_family(child.attrib['name']) + if namespace != 'creole': + family_name = namespace + '.' + family_name + self.paths.add_family(namespace, + family_name, + creoleobj, + ) + creoleobj.path = self.paths.get_family_path(family_name, namespace) def space_visitor(self, eosfunc_file): # pylint: disable=C0111 - ActionAnnotator(self) ServiceAnnotator(self) SpaceAnnotator(self, eosfunc_file) @@ -486,42 +521,13 @@ class CreoleObjSpace(object): :param filename: the full XML filename """ - xml = Element('creole') + xml = Element('rougail') self._xml_export(xml, self.space) if not force_no_save: self.xmlreflector.save_xmlfile(filename, xml) return xml - def save_probes(self, filename, force_no_save=False): - """Save an XML output on disk - - :param filename: the full XML filename - """ - ret = {} - for variable in self.probe_variables: - args = [] - kwargs = {} - if hasattr(variable, 'param'): - for param in variable.param: - list_param = list(vars(param).keys()) - if 'index' in list_param: - list_param.remove('index') - if list_param == ['text']: - args.append(param.text) - elif list_param == ['text', 'name']: - kwargs[param.name] = param.text - else: - print(vars(param)) - raise Exception('hu?') - ret[variable.target] = {'function': variable.name, - 'args': args, - 'kwargs': kwargs} - if not force_no_save: - with open(filename, 'w') as fhj: - dump(ret, fhj) - return ret - - def _get_attributes(self, space): # pylint: disable=R0201 + def get_attributes(self, space): # pylint: disable=R0201 for attr in dir(space): if not attr.startswith('_'): yield attr @@ -549,13 +555,13 @@ class CreoleObjSpace(object): child_node.attrib['name'] = name else: child_node = SubElement(node, name) - for subname in self._get_attributes(space): + for subname in self.get_attributes(space): subspace = getattr(space, subname) self._sub_xml_export(subname, child_node, name, subspace, space) elif isinstance(space, self.Redefinable): child_node = SubElement(node, 'family') child_node.attrib['name'] = name - for subname in self._get_attributes(space): + for subname in self.get_attributes(space): subspace = getattr(space, subname) self._sub_xml_export(subname, child_node, name, subspace, space) else: @@ -587,192 +593,6 @@ class CreoleObjSpace(object): node.attrib[name] = str(space) def _xml_export(self, node, space, node_name='creole'): - for name in self._get_attributes(space): + for name in self.get_attributes(space): subspace = getattr(space, name) self._sub_xml_export(name, node, node_name, subspace, space) - - -class Path: - """Helper class to handle the `path` attribute of a CreoleObjSpace - instance. - - sample: path="creole.general.condition" - """ - def __init__(self): - self.variables = {} - self.families = {} - - # Family - def add_family(self, - namespace: str, - name: str, - creoleobj: str, - ) -> str: # pylint: disable=C0111 - self.families[name] = dict(name=name, - namespace=namespace, - creoleobj=creoleobj, - ) - - def get_family_path(self, - name: str, - current_namespace: str, - ) -> str: # pylint: disable=C0111 - if current_namespace is None: # pragma: no cover - raise CreoleOperationError('current_namespace must not be None') - dico = self.families[normalize_family(name, - check_name=False, - allow_dot=True, - )] - if dico['namespace'] != 'creole' and current_namespace != dico['namespace']: - raise CreoleDictConsistencyError(_('A family located in the {} namespace ' - 'shall not be used in the {} namespace').format( - dico['namespace'], current_namespace)) - path = dico['name'] - if dico['namespace'] is not None and '.' not in dico['name']: - path = '.'.join([dico['namespace'], path]) - return path - - def get_family_namespace(self, - name: str, - ) -> str: # pylint: disable=C0111 - dico = self.families[name] - if dico['namespace'] is None: - return dico['name'] - return dico['namespace'] - - def get_family_obj(self, - name: str, - ) -> 'Family': # pylint: disable=C0111 - if name not in self.families: - raise CreoleDictConsistencyError(_('unknown family {}').format(name)) - dico = self.families[name] - return dico['creoleobj'] - - # Leadership - def set_leader(self, - namespace: str, - leader_family_name: str, - name: str, - leader_name: str, - ) -> None: # pylint: disable=C0111 - if namespace != 'creole': - # 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['creoleobj'], - ) - name = new_path - dico = self._get_variable(name) - if dico['leader'] != None: - raise CreoleDictConsistencyError(_('Already defined leader {} for variable' - ' {}'.format(dico['leader'], name))) - dico['leader'] = leader_name - - def get_leader(self, name): # pylint: disable=C0111 - return self._get_variable(name)['leader'] - - # Variable - def add_variable(self, - namespace: str, - name: str, - family: str, - is_dynamic: bool, - creoleobj, - ) -> str: # pylint: disable=C0111 - if namespace == 'creole' or '.' in name: - varname = name - else: - varname = '.'.join([namespace, family, name]) - self.variables[varname] = dict(name=name, - family=family, - namespace=namespace, - leader=None, - is_dynamic=is_dynamic, - creoleobj=creoleobj) - - def get_variable_name(self, - name, - ): # pylint: disable=C0111 - return self._get_variable(name)['name'] - - def get_variable_obj(self, - name:str, - ) -> 'Variable': # pylint: disable=C0111 - return self._get_variable(name)['creoleobj'] - - def get_variable_family_name(self, - name: str, - ) -> str: # pylint: disable=C0111 - return self._get_variable(name)['family'] - - def get_variable_family_path(self, - name: str, - ) -> str: # pylint: disable=C0111 - dico = self._get_variable(name) - list_path = [dico['namespace'], dico['family']] - if dico['leader'] is not None: - list_path.append(dico['leader']) - return '.'.join(list_path) - - def get_variable_namespace(self, - name: str, - ) -> str: # pylint: disable=C0111 - return self._get_variable(name)['namespace'] - - def get_variable_path(self, - name: str, - current_namespace: str, - allow_source: str=False, - with_suffix: bool=False, - ) -> str: # pylint: disable=C0111 - if current_namespace is None: # pragma: no cover - raise CreoleOperationError('current_namespace must not be None') - if with_suffix: - dico, suffix = self._get_variable(name, - with_suffix=True, - ) - else: - dico = self._get_variable(name) - if not allow_source: - if dico['namespace'] not in ['creole', 'services'] and current_namespace != dico['namespace']: - raise CreoleDictConsistencyError(_('A variable located in the {} namespace ' - 'shall not be used in the {} namespace').format( - dico['namespace'], current_namespace)) - 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) - if with_suffix: - return value, suffix - return value - - def path_is_defined(self, - name: str, - ) -> str: # pylint: disable=C0111 - return name in self.variables - - def _get_variable(self, - name: str, - with_suffix: bool=False, - ) -> str: - if name not in self.variables: - if name.startswith('creole.'): - name = name.split('.')[-1] - if name not in self.variables: - for var_name, variable in self.variables.items(): - if variable['is_dynamic'] and name.startswith(var_name): - return variable, name[len(var_name):] - raise CreoleDictConsistencyError(_('unknown option {}').format(name)) - if with_suffix: - return self.variables[name], None - return self.variables[name] diff --git a/src/rougail/path.py b/src/rougail/path.py new file mode 100644 index 000000000..9d7995ee5 --- /dev/null +++ b/src/rougail/path.py @@ -0,0 +1,182 @@ +from .i18n import _ +from .utils import normalize_family +from .error import CreoleOperationError, CreoleDictConsistencyError + + +class Path: + """Helper class to handle the `path` attribute of a CreoleObjSpace + instance. + + sample: path="creole.general.condition" + """ + def __init__(self): + self.variables = {} + self.families = {} + + # Family + def add_family(self, + namespace: str, + name: str, + creoleobj: str, + ) -> str: # pylint: disable=C0111 + self.families[name] = dict(name=name, + namespace=namespace, + creoleobj=creoleobj, + ) + + def get_family_path(self, + name: str, + current_namespace: str, + ) -> str: # pylint: disable=C0111 + if current_namespace is None: # pragma: no cover + raise CreoleOperationError('current_namespace must not be None') + dico = self.families[normalize_family(name, + check_name=False, + allow_dot=True, + )] + if dico['namespace'] != 'creole' and current_namespace != dico['namespace']: + raise CreoleDictConsistencyError(_('A family located in the {} namespace ' + 'shall not be used in the {} namespace').format( + dico['namespace'], current_namespace)) + path = dico['name'] + if dico['namespace'] is not None and '.' not in dico['name']: + path = '.'.join([dico['namespace'], path]) + return path + + def get_family_obj(self, + name: str, + ) -> 'Family': # pylint: disable=C0111 + if name not in self.families: + raise CreoleDictConsistencyError(_('unknown family {}').format(name)) + dico = self.families[name] + return dico['creoleobj'] + + # Leadership + def set_leader(self, + namespace: str, + leader_family_name: str, + name: str, + leader_name: str, + ) -> None: # pylint: disable=C0111 + if namespace != 'creole': + # 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['creoleobj'], + ) + name = new_path + dico = self._get_variable(name) + if dico['leader'] != None: + raise CreoleDictConsistencyError(_('Already defined leader {} for variable' + ' {}'.format(dico['leader'], name))) + dico['leader'] = leader_name + + def get_leader(self, name): # pylint: disable=C0111 + return self._get_variable(name)['leader'] + + # Variable + def add_variable(self, + namespace: str, + name: str, + family: str, + is_dynamic: bool, + creoleobj, + ) -> str: # pylint: disable=C0111 + if namespace == 'creole' or '.' in name: + varname = name + else: + varname = '.'.join([namespace, family, name]) + self.variables[varname] = dict(name=name, + family=family, + namespace=namespace, + leader=None, + is_dynamic=is_dynamic, + creoleobj=creoleobj) + + def get_variable_name(self, + name, + ): # pylint: disable=C0111 + return self._get_variable(name)['name'] + + def get_variable_obj(self, + name:str, + ) -> 'Variable': # pylint: disable=C0111 + return self._get_variable(name)['creoleobj'] + + def get_variable_family_name(self, + name: str, + ) -> str: # pylint: disable=C0111 + return self._get_variable(name)['family'] + + def get_variable_family_path(self, + name: str, + ) -> str: # pylint: disable=C0111 + dico = self._get_variable(name) + list_path = [dico['namespace'], dico['family']] + if dico['leader'] is not None: + list_path.append(dico['leader']) + return '.'.join(list_path) + + def get_variable_namespace(self, + name: str, + ) -> str: # pylint: disable=C0111 + return self._get_variable(name)['namespace'] + + def get_variable_path(self, + name: str, + current_namespace: str, + allow_source: str=False, + with_suffix: bool=False, + ) -> str: # pylint: disable=C0111 + if current_namespace is None: # pragma: no cover + raise CreoleOperationError('current_namespace must not be None') + if with_suffix: + dico, suffix = self._get_variable(name, + with_suffix=True, + ) + else: + dico = self._get_variable(name) + if not allow_source: + if dico['namespace'] not in ['creole', 'services'] and current_namespace != dico['namespace']: + raise CreoleDictConsistencyError(_('A variable located in the {} namespace ' + 'shall not be used in the {} namespace').format( + dico['namespace'], current_namespace)) + 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) + if with_suffix: + return value, suffix + return value + + def path_is_defined(self, + name: str, + ) -> str: # pylint: disable=C0111 + return name in self.variables + + def _get_variable(self, + name: str, + with_suffix: bool=False, + ) -> str: + if name not in self.variables: + if name.startswith('creole.'): + name = name.split('.')[-1] + if name not in self.variables: + for var_name, variable in self.variables.items(): + if variable['is_dynamic'] and name.startswith(var_name): + return variable, name[len(var_name):] + raise CreoleDictConsistencyError(_('unknown option {}').format(name)) + 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 59436b2ef..6b0f0bbfd 100644 --- a/src/rougail/xmlreflector.py +++ b/src/rougail/xmlreflector.py @@ -35,58 +35,53 @@ class XMLReflector(object): :returns: the root element tree object """ - # FIXME zephir2 # document = parse(BytesIO(xmlfile), XMLParser(remove_blank_text=True)) document = parse(xmlfile) if not self.dtd.validate(document): raise CreoleDictConsistencyError(_("not a valid xml file: {}").format(xmlfile)) return document.getroot() - def load_xml_from_folders(self, xmlfolders, from_zephir): + def load_xml_from_folders(self, xmlfolders): """Loads all the XML files located in the xmlfolders' list :param xmlfolders: list of full folder's name """ documents = [] - if from_zephir: - for idx, xmlfile in enumerate(xmlfolders): - documents.append(('generate_{}'.format(idx), self.parse_xmlfile(xmlfile, from_zephir=from_zephir))) - else: - if not isinstance(xmlfolders, list): - xmlfolders = [xmlfolders] - for xmlfolder in xmlfolders: - if isinstance(xmlfolder, list) or isinstance(xmlfolder, tuple): - # directory group : collect files from each - # directory and sort them before loading - group_files = [] - for idx, subdir in enumerate(xmlfolder): - if isdir(subdir): - for filename in listdir(subdir): - group_files.append((filename, idx, subdir)) - else: - group_files.append(basename(subdir), idx, dirname(subdir)) - def sort_group(file1, file2): - if file1[0] == file2[0]: - # sort by initial xmlfolder order if same name - return file1[1].__cmp__(file2[1]) - # sort by filename - elif file1[0] > file2[0]: - return 1 - else: - return -1 - group_files.sort(sort_group) - filenames = [join(f[2], f[0]) for f in group_files] - elif isdir(xmlfolder): - filenames = [] - for filename in listdir(xmlfolder): - filenames.append(join(xmlfolder, filename)) - filenames.sort() - else: - filenames = [xmlfolder] - for xmlfile in filenames: - if xmlfile.endswith('.xml'): - #xmlfile_path = join(xmlfolder, xmlfile) - documents.append((xmlfile, self.parse_xmlfile(xmlfile))) + if not isinstance(xmlfolders, list): + xmlfolders = [xmlfolders] + for xmlfolder in xmlfolders: + if isinstance(xmlfolder, list) or isinstance(xmlfolder, tuple): + # directory group : collect files from each + # directory and sort them before loading + group_files = [] + for idx, subdir in enumerate(xmlfolder): + if isdir(subdir): + for filename in listdir(subdir): + group_files.append((filename, idx, subdir)) + else: + group_files.append(basename(subdir), idx, dirname(subdir)) + def sort_group(file1, file2): + if file1[0] == file2[0]: + # sort by initial xmlfolder order if same name + return file1[1].__cmp__(file2[1]) + # sort by filename + elif file1[0] > file2[0]: + return 1 + else: + return -1 + group_files.sort(sort_group) + filenames = [join(f[2], f[0]) for f in group_files] + elif isdir(xmlfolder): + filenames = [] + for filename in listdir(xmlfolder): + filenames.append(join(xmlfolder, filename)) + filenames.sort() + else: + filenames = [xmlfolder] + for xmlfile in filenames: + if xmlfile.endswith('.xml'): + #xmlfile_path = join(xmlfolder, xmlfile) + documents.append((xmlfile, self.parse_xmlfile(xmlfile))) return documents def save_xmlfile(self, xmlfilename, xml): # pylint: disable=R0201 diff --git a/tests/eosfunc/test.py b/tests/eosfunc/test.py index 638625f1d..210a332ef 100644 --- a/tests/eosfunc/test.py +++ b/tests/eosfunc/test.py @@ -59,3 +59,7 @@ def cdrom_minormajor(*args, **kwargs): def device_type(*args, **kwargs): pass + + +def calc_list(*args, **kwargs): + return [] diff --git a/tests/flattener_dicos/00empty/result/00-base.xml b/tests/flattener_dicos/00empty/result/00-base.xml index 320698ef4..944cc0835 100644 --- a/tests/flattener_dicos/00empty/result/00-base.xml +++ b/tests/flattener_dicos/00empty/result/00-base.xml @@ -1,8 +1,6 @@ - + - - basic - + - + diff --git a/tests/flattener_dicos/00load_autofreeze/result/00-base.xml b/tests/flattener_dicos/00load_autofreeze/result/00-base.xml index 5480153d9..7cb08d619 100644 --- a/tests/flattener_dicos/00load_autofreeze/result/00-base.xml +++ b/tests/flattener_dicos/00load_autofreeze/result/00-base.xml @@ -1,5 +1,5 @@ - + basic @@ -23,4 +23,4 @@ - + diff --git a/tests/flattener_dicos/00load_autofreezeexpert/result/00-base.xml b/tests/flattener_dicos/00load_autofreezeexpert/result/00-base.xml index c7505ff34..0c50974cb 100644 --- a/tests/flattener_dicos/00load_autofreezeexpert/result/00-base.xml +++ b/tests/flattener_dicos/00load_autofreezeexpert/result/00-base.xml @@ -1,5 +1,5 @@ - + normal @@ -23,4 +23,4 @@ - + diff --git a/tests/flattener_dicos/00load_autosave/result/00-base.xml b/tests/flattener_dicos/00load_autosave/result/00-base.xml index f9a036dc7..e85260bf1 100644 --- a/tests/flattener_dicos/00load_autosave/result/00-base.xml +++ b/tests/flattener_dicos/00load_autosave/result/00-base.xml @@ -1,5 +1,5 @@ - + basic @@ -14,4 +14,4 @@ - + diff --git a/tests/flattener_dicos/00load_autosaveexpert/result/00-base.xml b/tests/flattener_dicos/00load_autosaveexpert/result/00-base.xml index e20230d3e..62b4e9783 100644 --- a/tests/flattener_dicos/00load_autosaveexpert/result/00-base.xml +++ b/tests/flattener_dicos/00load_autosaveexpert/result/00-base.xml @@ -1,5 +1,5 @@ - + expert @@ -14,4 +14,4 @@ - + diff --git a/tests/flattener_dicos/00load_comment/makedict/base.json b/tests/flattener_dicos/00load_comment/makedict/base.json new file mode 100644 index 000000000..f06f2ed8f --- /dev/null +++ b/tests/flattener_dicos/00load_comment/makedict/base.json @@ -0,0 +1 @@ +{"creole.general.mode_conteneur_actif": "non"} diff --git a/tests/flattener_dicos/00load_comment/result/00-base.xml b/tests/flattener_dicos/00load_comment/result/00-base.xml index 7231f218b..1a57bb8d3 100644 --- a/tests/flattener_dicos/00load_comment/result/00-base.xml +++ b/tests/flattener_dicos/00load_comment/result/00-base.xml @@ -1,5 +1,5 @@ - + normal @@ -16,4 +16,4 @@ - + diff --git a/tests/flattener_dicos/00load_notype/makedict/base.json b/tests/flattener_dicos/00load_notype/makedict/base.json index 87b2ec3b7..b13db1605 100644 --- a/tests/flattener_dicos/00load_notype/makedict/base.json +++ b/tests/flattener_dicos/00load_notype/makedict/base.json @@ -1 +1 @@ -{"creole.general.without_type": "non"} +{"creole.general.mode_conteneur_actif": "non", "creole.general.without_type": "non"} diff --git a/tests/flattener_dicos/00load_notype/result/00-base.xml b/tests/flattener_dicos/00load_notype/result/00-base.xml index 68bd88a8a..54fe43d1f 100644 --- a/tests/flattener_dicos/00load_notype/result/00-base.xml +++ b/tests/flattener_dicos/00load_notype/result/00-base.xml @@ -1,5 +1,5 @@ - + normal @@ -21,4 +21,4 @@ - + diff --git a/tests/flattener_dicos/00load_save/makedict/base.json b/tests/flattener_dicos/00load_save/makedict/base.json new file mode 100644 index 000000000..f06f2ed8f --- /dev/null +++ b/tests/flattener_dicos/00load_save/makedict/base.json @@ -0,0 +1 @@ +{"creole.general.mode_conteneur_actif": "non"} diff --git a/tests/flattener_dicos/00load_save/result/00-base.xml b/tests/flattener_dicos/00load_save/result/00-base.xml index 7231f218b..1a57bb8d3 100644 --- a/tests/flattener_dicos/00load_save/result/00-base.xml +++ b/tests/flattener_dicos/00load_save/result/00-base.xml @@ -1,5 +1,5 @@ - + normal @@ -16,4 +16,4 @@ - + diff --git a/tests/flattener_dicos/00load_subfolder/makedict/base.json b/tests/flattener_dicos/00load_subfolder/makedict/base.json new file mode 100644 index 000000000..dcccb00c8 --- /dev/null +++ b/tests/flattener_dicos/00load_subfolder/makedict/base.json @@ -0,0 +1 @@ +{"creole.general.mode_conteneur_actif": "non", "creole.general.mode_conteneur_actif1": "non"} diff --git a/tests/flattener_dicos/00load_subfolder/result/00-base.xml b/tests/flattener_dicos/00load_subfolder/result/00-base.xml index fb91ca91d..f7e00d905 100644 --- a/tests/flattener_dicos/00load_subfolder/result/00-base.xml +++ b/tests/flattener_dicos/00load_subfolder/result/00-base.xml @@ -1,5 +1,5 @@ - + normal @@ -26,4 +26,4 @@ - + diff --git a/tests/flattener_dicos/01auto_base/00-base.xml b/tests/flattener_dicos/01auto_base/00-base.xml index 58619ec92..edf7fd205 100644 --- a/tests/flattener_dicos/01auto_base/00-base.xml +++ b/tests/flattener_dicos/01auto_base/00-base.xml @@ -16,9 +16,9 @@ - + mode_conteneur_actif1 - + diff --git a/tests/flattener_dicos/01auto_base/makedict/base.json b/tests/flattener_dicos/01auto_base/makedict/base.json index 8f8f47c66..530abf249 100644 --- a/tests/flattener_dicos/01auto_base/makedict/base.json +++ b/tests/flattener_dicos/01auto_base/makedict/base.json @@ -1 +1 @@ -{"creole.general.mode_conteneur_actif1": "non"} +{"creole.general.mode_conteneur_actif": null, "creole.general.mode_conteneur_actif1": "non"} diff --git a/tests/flattener_dicos/01auto_base/result/00-base.xml b/tests/flattener_dicos/01auto_base/result/00-base.xml index e76c5ccd0..5ff153fba 100644 --- a/tests/flattener_dicos/01auto_base/result/00-base.xml +++ b/tests/flattener_dicos/01auto_base/result/00-base.xml @@ -1,5 +1,5 @@ - + normal @@ -25,4 +25,4 @@ - + diff --git a/tests/flattener_dicos/01auto_withoutparam/00-base.xml b/tests/flattener_dicos/01auto_withoutparam/00-base.xml index 4808a5416..5c07d2c39 100644 --- a/tests/flattener_dicos/01auto_withoutparam/00-base.xml +++ b/tests/flattener_dicos/01auto_withoutparam/00-base.xml @@ -16,8 +16,8 @@ - - + + diff --git a/tests/flattener_dicos/01auto_withoutparam/makedict/base.json b/tests/flattener_dicos/01auto_withoutparam/makedict/base.json index 8f8f47c66..530abf249 100644 --- a/tests/flattener_dicos/01auto_withoutparam/makedict/base.json +++ b/tests/flattener_dicos/01auto_withoutparam/makedict/base.json @@ -1 +1 @@ -{"creole.general.mode_conteneur_actif1": "non"} +{"creole.general.mode_conteneur_actif": null, "creole.general.mode_conteneur_actif1": "non"} diff --git a/tests/flattener_dicos/01auto_withoutparam/result/00-base.xml b/tests/flattener_dicos/01auto_withoutparam/result/00-base.xml index 7fa50bee2..441dc24b1 100644 --- a/tests/flattener_dicos/01auto_withoutparam/result/00-base.xml +++ b/tests/flattener_dicos/01auto_withoutparam/result/00-base.xml @@ -1,5 +1,5 @@ - + normal @@ -23,4 +23,4 @@ - + diff --git a/tests/flattener_dicos/01base_multi/makedict/base.json b/tests/flattener_dicos/01base_multi/makedict/base.json new file mode 100644 index 000000000..f4597deac --- /dev/null +++ b/tests/flattener_dicos/01base_multi/makedict/base.json @@ -0,0 +1 @@ +{"creole.general.mode_conteneur_actif": ["non"]} diff --git a/tests/flattener_dicos/01base_multi/result/00-base.xml b/tests/flattener_dicos/01base_multi/result/00-base.xml index d8cc69164..aa8240e07 100644 --- a/tests/flattener_dicos/01base_multi/result/00-base.xml +++ b/tests/flattener_dicos/01base_multi/result/00-base.xml @@ -1,5 +1,5 @@ - + normal @@ -16,4 +16,4 @@ - + diff --git a/tests/flattener_dicos/01base_submulti/makedict/base.json b/tests/flattener_dicos/01base_submulti/makedict/base.json new file mode 100644 index 000000000..179a0b61c --- /dev/null +++ b/tests/flattener_dicos/01base_submulti/makedict/base.json @@ -0,0 +1 @@ +{"creole.general.mode_conteneur_actif": [["non"]]} diff --git a/tests/flattener_dicos/01base_submulti/result/00-base.xml b/tests/flattener_dicos/01base_submulti/result/00-base.xml index 87e8da222..e0085fb3c 100644 --- a/tests/flattener_dicos/01base_submulti/result/00-base.xml +++ b/tests/flattener_dicos/01base_submulti/result/00-base.xml @@ -1,5 +1,5 @@ - + normal @@ -16,4 +16,4 @@ - + diff --git a/tests/flattener_dicos/01fill_autofreeze/result/00-base.xml b/tests/flattener_dicos/01fill_autofreeze/result/00-base.xml index 7b53c763a..7af4a94e9 100644 --- a/tests/flattener_dicos/01fill_autofreeze/result/00-base.xml +++ b/tests/flattener_dicos/01fill_autofreeze/result/00-base.xml @@ -1,5 +1,5 @@ - + basic @@ -32,4 +32,4 @@ - + diff --git a/tests/flattener_dicos/01fill_autosave/result/00-base.xml b/tests/flattener_dicos/01fill_autosave/result/00-base.xml index a55ea99b9..79cae5909 100644 --- a/tests/flattener_dicos/01fill_autosave/result/00-base.xml +++ b/tests/flattener_dicos/01fill_autosave/result/00-base.xml @@ -1,5 +1,5 @@ - + basic @@ -23,4 +23,4 @@ - + diff --git a/tests/flattener_dicos/01fill_base/makedict/base.json b/tests/flattener_dicos/01fill_base/makedict/base.json index 8f8f47c66..530abf249 100644 --- a/tests/flattener_dicos/01fill_base/makedict/base.json +++ b/tests/flattener_dicos/01fill_base/makedict/base.json @@ -1 +1 @@ -{"creole.general.mode_conteneur_actif1": "non"} +{"creole.general.mode_conteneur_actif": null, "creole.general.mode_conteneur_actif1": "non"} diff --git a/tests/flattener_dicos/01fill_base/result/00-base.xml b/tests/flattener_dicos/01fill_base/result/00-base.xml index e76c5ccd0..5ff153fba 100644 --- a/tests/flattener_dicos/01fill_base/result/00-base.xml +++ b/tests/flattener_dicos/01fill_base/result/00-base.xml @@ -1,5 +1,5 @@ - + normal @@ -25,4 +25,4 @@ - + diff --git a/tests/flattener_dicos/01fill_baseaccent/makedict/base.json b/tests/flattener_dicos/01fill_baseaccent/makedict/base.json index 8f8f47c66..530abf249 100644 --- a/tests/flattener_dicos/01fill_baseaccent/makedict/base.json +++ b/tests/flattener_dicos/01fill_baseaccent/makedict/base.json @@ -1 +1 @@ -{"creole.general.mode_conteneur_actif1": "non"} +{"creole.general.mode_conteneur_actif": null, "creole.general.mode_conteneur_actif1": "non"} diff --git a/tests/flattener_dicos/01fill_baseaccent/result/00-base.xml b/tests/flattener_dicos/01fill_baseaccent/result/00-base.xml index b9bb3da1c..ef70b6a8e 100644 --- a/tests/flattener_dicos/01fill_baseaccent/result/00-base.xml +++ b/tests/flattener_dicos/01fill_baseaccent/result/00-base.xml @@ -1,5 +1,5 @@ - + normal @@ -25,4 +25,4 @@ - + diff --git a/tests/flattener_dicos/01fill_mandatory/result/00-base.xml b/tests/flattener_dicos/01fill_mandatory/result/00-base.xml index 5d713d37f..57be5d286 100644 --- a/tests/flattener_dicos/01fill_mandatory/result/00-base.xml +++ b/tests/flattener_dicos/01fill_mandatory/result/00-base.xml @@ -1,5 +1,5 @@ - + normal @@ -20,4 +20,4 @@ - + diff --git a/tests/flattener_dicos/01fill_number/makedict/base.json b/tests/flattener_dicos/01fill_number/makedict/base.json index 8f8f47c66..530abf249 100644 --- a/tests/flattener_dicos/01fill_number/makedict/base.json +++ b/tests/flattener_dicos/01fill_number/makedict/base.json @@ -1 +1 @@ -{"creole.general.mode_conteneur_actif1": "non"} +{"creole.general.mode_conteneur_actif": null, "creole.general.mode_conteneur_actif1": "non"} diff --git a/tests/flattener_dicos/01fill_number/result/00-base.xml b/tests/flattener_dicos/01fill_number/result/00-base.xml index c3cc42a5f..2a3c6c80e 100644 --- a/tests/flattener_dicos/01fill_number/result/00-base.xml +++ b/tests/flattener_dicos/01fill_number/result/00-base.xml @@ -1,5 +1,5 @@ - + normal @@ -22,4 +22,4 @@ - + diff --git a/tests/flattener_dicos/01fill_optional/makedict/base.json b/tests/flattener_dicos/01fill_optional/makedict/base.json index 8f8f47c66..530abf249 100644 --- a/tests/flattener_dicos/01fill_optional/makedict/base.json +++ b/tests/flattener_dicos/01fill_optional/makedict/base.json @@ -1 +1 @@ -{"creole.general.mode_conteneur_actif1": "non"} +{"creole.general.mode_conteneur_actif": null, "creole.general.mode_conteneur_actif1": "non"} diff --git a/tests/flattener_dicos/01fill_optional/result/00-base.xml b/tests/flattener_dicos/01fill_optional/result/00-base.xml index e76c5ccd0..5ff153fba 100644 --- a/tests/flattener_dicos/01fill_optional/result/00-base.xml +++ b/tests/flattener_dicos/01fill_optional/result/00-base.xml @@ -1,5 +1,5 @@ - + normal @@ -25,4 +25,4 @@ - + diff --git a/tests/flattener_dicos/01separator_base/makedict/base.json b/tests/flattener_dicos/01separator_base/makedict/base.json new file mode 100644 index 000000000..f06f2ed8f --- /dev/null +++ b/tests/flattener_dicos/01separator_base/makedict/base.json @@ -0,0 +1 @@ +{"creole.general.mode_conteneur_actif": "non"} diff --git a/tests/flattener_dicos/01separator_base/result/00-base.xml b/tests/flattener_dicos/01separator_base/result/00-base.xml index d5863e5e6..026c68d45 100644 --- a/tests/flattener_dicos/01separator_base/result/00-base.xml +++ b/tests/flattener_dicos/01separator_base/result/00-base.xml @@ -1,5 +1,5 @@ - + normal @@ -18,4 +18,4 @@ Établissement - + diff --git a/tests/flattener_dicos/01separator_neverhidden/makedict/base.json b/tests/flattener_dicos/01separator_neverhidden/makedict/base.json new file mode 100644 index 000000000..f06f2ed8f --- /dev/null +++ b/tests/flattener_dicos/01separator_neverhidden/makedict/base.json @@ -0,0 +1 @@ +{"creole.general.mode_conteneur_actif": "non"} diff --git a/tests/flattener_dicos/01separator_neverhidden/result/00-base.xml b/tests/flattener_dicos/01separator_neverhidden/result/00-base.xml index eb290e2e4..46dede284 100644 --- a/tests/flattener_dicos/01separator_neverhidden/result/00-base.xml +++ b/tests/flattener_dicos/01separator_neverhidden/result/00-base.xml @@ -1,5 +1,5 @@ - + normal @@ -18,4 +18,4 @@ Établissement - + diff --git a/tests/flattener_dicos/10autosave_hidden/makedict/base.json b/tests/flattener_dicos/10autosave_hidden/makedict/base.json new file mode 100644 index 000000000..359ba452e --- /dev/null +++ b/tests/flattener_dicos/10autosave_hidden/makedict/base.json @@ -0,0 +1 @@ +{"creole.general.mode_conteneur_actif": "non", "creole.general.autosavevar": null} diff --git a/tests/flattener_dicos/10autosave_hidden/result/00-base.xml b/tests/flattener_dicos/10autosave_hidden/result/00-base.xml index 1e686273f..2a31fb2e4 100644 --- a/tests/flattener_dicos/10autosave_hidden/result/00-base.xml +++ b/tests/flattener_dicos/10autosave_hidden/result/00-base.xml @@ -1,5 +1,5 @@ - + basic @@ -25,4 +25,4 @@ - + diff --git a/tests/flattener_dicos/10autosave_hidden_frozenifin/makedict/base.json b/tests/flattener_dicos/10autosave_hidden_frozenifin/makedict/base.json index fb8fd49fe..359ba452e 100644 --- a/tests/flattener_dicos/10autosave_hidden_frozenifin/makedict/base.json +++ b/tests/flattener_dicos/10autosave_hidden_frozenifin/makedict/base.json @@ -1 +1 @@ -{"creole.general.autosavevar": null} +{"creole.general.mode_conteneur_actif": "non", "creole.general.autosavevar": null} diff --git a/tests/flattener_dicos/10autosave_hidden_frozenifin/result/00-base.xml b/tests/flattener_dicos/10autosave_hidden_frozenifin/result/00-base.xml index 7a9264be0..e00e90355 100644 --- a/tests/flattener_dicos/10autosave_hidden_frozenifin/result/00-base.xml +++ b/tests/flattener_dicos/10autosave_hidden_frozenifin/result/00-base.xml @@ -1,5 +1,5 @@ - + basic @@ -26,4 +26,4 @@ - + diff --git a/tests/flattener_dicos/10check_base/result/00-base.xml b/tests/flattener_dicos/10check_base/result/00-base.xml index e2e286c93..908f8585e 100644 --- a/tests/flattener_dicos/10check_base/result/00-base.xml +++ b/tests/flattener_dicos/10check_base/result/00-base.xml @@ -1,5 +1,5 @@ - + normal @@ -18,4 +18,4 @@ - + diff --git a/tests/flattener_dicos/10check_option/result/00-base.xml b/tests/flattener_dicos/10check_option/result/00-base.xml index ab96be9f9..967c5ecfa 100644 --- a/tests/flattener_dicos/10check_option/result/00-base.xml +++ b/tests/flattener_dicos/10check_option/result/00-base.xml @@ -1,5 +1,5 @@ - + normal @@ -23,4 +23,4 @@ - + diff --git a/tests/flattener_dicos/10check_optional/result/00-base.xml b/tests/flattener_dicos/10check_optional/result/00-base.xml index 88b10e62a..9cc336e6b 100644 --- a/tests/flattener_dicos/10check_optional/result/00-base.xml +++ b/tests/flattener_dicos/10check_optional/result/00-base.xml @@ -1,5 +1,5 @@ - + normal @@ -21,4 +21,4 @@ - + diff --git a/tests/flattener_dicos/10check_valid_differ/result/00-base.xml b/tests/flattener_dicos/10check_valid_differ/result/00-base.xml index 0d40273bd..9b36f7868 100644 --- a/tests/flattener_dicos/10check_valid_differ/result/00-base.xml +++ b/tests/flattener_dicos/10check_valid_differ/result/00-base.xml @@ -1,5 +1,5 @@ - + normal @@ -23,4 +23,4 @@ - + diff --git a/tests/flattener_dicos/10check_valid_differ_add/result/00-base.xml b/tests/flattener_dicos/10check_valid_differ_add/result/00-base.xml index fc596149a..498755777 100644 --- a/tests/flattener_dicos/10check_valid_differ_add/result/00-base.xml +++ b/tests/flattener_dicos/10check_valid_differ_add/result/00-base.xml @@ -1,5 +1,5 @@ - + normal @@ -44,4 +44,4 @@ - + diff --git a/tests/flattener_dicos/10check_valid_differ_removecheck/result/00-base.xml b/tests/flattener_dicos/10check_valid_differ_removecheck/result/00-base.xml index d3646abda..a6cee7416 100644 --- a/tests/flattener_dicos/10check_valid_differ_removecheck/result/00-base.xml +++ b/tests/flattener_dicos/10check_valid_differ_removecheck/result/00-base.xml @@ -1,5 +1,5 @@ - + normal @@ -38,4 +38,4 @@ - + diff --git a/tests/flattener_dicos/10check_valid_ipnetmask/result/00-base.xml b/tests/flattener_dicos/10check_valid_ipnetmask/result/00-base.xml index 73b07ef5e..5bbc5953b 100644 --- a/tests/flattener_dicos/10check_valid_ipnetmask/result/00-base.xml +++ b/tests/flattener_dicos/10check_valid_ipnetmask/result/00-base.xml @@ -1,5 +1,5 @@ - + basic @@ -24,4 +24,4 @@ - + diff --git a/tests/flattener_dicos/10leadership_append/result/00-base.xml b/tests/flattener_dicos/10leadership_append/result/00-base.xml index 4b8d10246..b3d76d329 100644 --- a/tests/flattener_dicos/10leadership_append/result/00-base.xml +++ b/tests/flattener_dicos/10leadership_append/result/00-base.xml @@ -1,5 +1,5 @@ - + normal @@ -34,4 +34,4 @@ - + diff --git a/tests/flattener_dicos/10leadership_auto/00-base.xml b/tests/flattener_dicos/10leadership_auto/00-base.xml index 7d9f1ca28..fd7d172c2 100644 --- a/tests/flattener_dicos/10leadership_auto/00-base.xml +++ b/tests/flattener_dicos/10leadership_auto/00-base.xml @@ -9,22 +9,22 @@ non - - - +