From e34d285eb3b873dbd9a3bfbe090bf5833f5f4cd1 Mon Sep 17 00:00:00 2001 From: Emmanuel Garette Date: Sat, 16 Jan 2021 08:50:11 +0100 Subject: [PATCH] manage group --- src/rougail/annotator/constrainte.py | 41 ++++++++++++++++------------ src/rougail/annotator/group.py | 27 ++++++++++-------- src/rougail/objspace.py | 4 +-- src/rougail/path.py | 27 ++++++++++++------ src/rougail/tiramisureflector.py | 2 +- tests/test_1_flattener.py | 4 ++- 6 files changed, 63 insertions(+), 42 deletions(-) diff --git a/src/rougail/annotator/constrainte.py b/src/rougail/annotator/constrainte.py index 38cca26f..a497c057 100644 --- a/src/rougail/annotator/constrainte.py +++ b/src/rougail/annotator/constrainte.py @@ -62,6 +62,7 @@ class ConstrainteAnnotator: self.convert_condition_target() self.convert_xxxlist_to_variable() self.check_condition_fallback_optional() + self.convert_condition_source() self.check_choice_option_condition() self.remove_condition_with_empty_target() self.convert_condition() @@ -116,7 +117,7 @@ class ConstrainteAnnotator: xmlfiles = self.objectspace.display_xmlfiles(check.xmlfiles) msg = _(f'cannot find check function "{check.name}" in {xmlfiles}') raise DictConsistencyError(msg, 1) - check.is_in_leadership = self.objectspace.paths.get_leader(check.target) is not None + check.is_in_leadership = self.objectspace.paths.is_in_leadership(check.target) # let's replace the target by the path try: check.target = self.objectspace.paths.get_variable_obj(check.target) @@ -278,11 +279,12 @@ class ConstrainteAnnotator: ): if target.type == 'variable': variable = self.objectspace.paths.get_variable_obj(target.name) - family = self.objectspace.paths.get_family(target.name.rsplit('.', 1)[0], - variable.namespace, - ) # it's a leader, so apply property to leadership - if isinstance(family, self.objectspace.leadership) and family.variable[0].name == variable.name: + if self.objectspace.paths.is_leader(target.name): + family_name = self.objectspace.paths.get_variable_family_path(target.name) + family = self.objectspace.paths.get_family(target.name.rsplit('.', 1)[0], + variable.namespace, + ) return family, family.variable return variable, [variable] # it's a family @@ -408,25 +410,30 @@ class ConstrainteAnnotator: for variable in variables: setattr(variable, action, True) + def convert_condition_source(self): + """remove condition for ChoiceOption that don't have param + """ + remove_conditions = [] + for condition_idx, condition in enumerate(self.objectspace.space.constraints.condition): + try: + condition.source = self.objectspace.paths.get_variable_obj(condition.source) + except DictConsistencyError as err: + if err.errno == 36: + xmlfiles = self.objectspace.display_xmlfiles(condition.xmlfiles) + msg = _(f'the source "{condition.source}" in condition cannot be a dynamic ' + f'variable in {xmlfiles}') + raise DictConsistencyError(msg, 20) + def check_choice_option_condition(self): """remove condition for ChoiceOption that don't have param """ remove_conditions = [] for condition_idx, condition in enumerate(self.objectspace.space.constraints.condition): namespace = condition.namespace - condition.source, suffix = self.objectspace.paths.get_variable_path(condition.source, - namespace, - allow_source=True, - ) - if suffix: - xmlfiles = self.objectspace.display_xmlfiles(condition.xmlfiles) - msg = _(f'the source "{condition.source}" in condition cannot be a dynamic ' - f'variable in {xmlfiles}') - raise DictConsistencyError(msg, 20) # FIXME only string? - if condition.source in self.valid_enums and \ - self.valid_enums[condition.source]['type'] == 'string': - valid_enum = self.valid_enums[condition.source]['values'] + if condition.source.path in self.valid_enums and \ + self.valid_enums[condition.source.path]['type'] == 'string': + valid_enum = self.valid_enums[condition.source.path]['values'] remove_param = [param_idx for param_idx, param in enumerate(condition.param) \ if param.text not in valid_enum] remove_param.sort(reverse=True) diff --git a/src/rougail/annotator/group.py b/src/rougail/annotator/group.py index b00767ee..b696373b 100644 --- a/src/rougail/annotator/group.py +++ b/src/rougail/annotator/group.py @@ -22,22 +22,26 @@ class GroupAnnotator: def convert_groups(self): # pylint: disable=C0111 """convert groups """ + cache_paths = {} for group in self.objectspace.space.constraints.group: leader_fullname = group.leader leader = self.objectspace.paths.get_variable_obj(leader_fullname) - leader_family_name = self.objectspace.paths.get_variable_family_name(leader_fullname) + if leader_fullname in cache_paths: + leader_family_path = cache_paths[leader_fullname] + else: + leader_family_path = self.objectspace.paths.get_variable_family_path(leader_fullname) + cache_paths[leader_fullname] = leader_family_path if '.' not in leader_fullname: - leader_fullname = '.'.join([leader.namespace, leader_family_name, leader_fullname]) + leader_fullname = '.'.join([leader_family_path, leader_fullname]) follower_names = list(group.follower.keys()) - leader_family = leader_fullname.rsplit('.', 1)[0] - ori_leader_family = self.objectspace.paths.get_family(leader_family, + ori_leader_family = self.objectspace.paths.get_family(leader_family_path, leader.namespace, ) has_a_leader = False for variable in list(ori_leader_family.variable.values()): if has_a_leader: # it's a follower - self.manage_follower(leader_family_name, + self.manage_follower(leader_family_path, variable, leadership_name, follower_names, @@ -64,13 +68,12 @@ class GroupAnnotator: else: leadership_name = leader.name leader_is_hidden = self.manage_leader(leader_space, - leader_family_name, + leader_family_path, leadership_name, leader.name, variable, group, ) - leader_space.path = leader_fullname has_a_leader = True else: xmlfiles = self.objectspace.display_xmlfiles(variable.xmlfiles) @@ -111,25 +114,25 @@ class GroupAnnotator: else: leader_space.doc = leadership_name namespace = variable.namespace - leadership_path = namespace + '.' + leader_family_name + '.' + leadership_name + leadership_path = leader_family_name + '.' + leadership_name self.objectspace.paths.add_leadership(namespace, leadership_path, leader_space, ) - leader_family = self.objectspace.space.variables[namespace].family[leader_family_name] + leader_family = self.objectspace.space.variables[namespace].family[leader_family_name.rsplit('.', 1)[-1]] leader_family.variable[leader_name] = leader_space leader_space.variable.append(variable) self.objectspace.paths.set_leader(namespace, leader_family_name, - leader_name, leadership_name, + leader_name, ) return leader_is_hidden def manage_follower(self, leader_family_name: str, variable: 'Variable', - leader_name: str, + leadership_name: str, follower_names: List[str], ) -> None: """manage follower @@ -142,6 +145,6 @@ class GroupAnnotator: raise DictConsistencyError(msg, 33) self.objectspace.paths.set_leader(variable.namespace, leader_family_name, + leadership_name, variable.name, - leader_name, ) diff --git a/src/rougail/objspace.py b/src/rougail/objspace.py index 09381f66..1741562e 100644 --- a/src/rougail/objspace.py +++ b/src/rougail/objspace.py @@ -312,7 +312,7 @@ class RougailObjSpace: name = space.path + '.' + name if not self.paths.path_is_defined(name): return None - old_family_name = namespace + '.' + self.paths.get_variable_family_name(name) + old_family_name = self.paths.get_variable_family_path(name) if space.path != old_family_name: xmlfiles = self.display_xmlfiles(space.xmlfiles) msg = _(f'Variable was previously create in family "{old_family_name}", ' @@ -437,7 +437,7 @@ class RougailObjSpace: family_name = normalize_family(document.attrib['name']) self.paths.add_variable(namespace, variableobj.name, - family_name, + namespace + '.' + family_name, document.attrib.get('dynamic') is not None, variableobj, ) diff --git a/src/rougail/path.py b/src/rougail/path.py index 2125c564..ceb93727 100644 --- a/src/rougail/path.py +++ b/src/rougail/path.py @@ -78,20 +78,29 @@ class Path: def set_leader(self, namespace: str, leader_family_name: str, + leadership_name: str, name: str, - leader_name: str, ) -> None: # pylint: disable=C0111 # need rebuild path and move object in new path - old_path = namespace + '.' + leader_family_name + '.' + name - new_path = namespace + '.' + leader_family_name + '.' + leader_name + '.' + name + old_path = leader_family_name + '.' + name + leadership_path = leader_family_name + '.' + leadership_name + new_path = leadership_path + '.' + name self.variables[new_path] = self.variables.pop(old_path) - self.variables[new_path]['leader'] = leader_name + self.variables[new_path]['leader'] = leadership_path self.variables[new_path]['variableobj'].path = new_path + self.variables[new_path]['family'] = leadership_path if namespace == Config['variable_namespace']: self.full_paths_variables[name] = new_path - def get_leader(self, name): # pylint: disable=C0111 - return self._get_variable(name)['leader'] + def is_in_leadership(self, name): + return self._get_variable(name)['leader'] is not None + + def is_leader(self, path): # pylint: disable=C0111 + variable = self._get_variable(path) + if not variable['leader']: + return False + leadership = self.get_family(variable['leader'], variable['variableobj'].namespace) + return leadership.variable[0].path == path # Variable def add_variable(self, @@ -102,7 +111,7 @@ class Path: variableobj, ) -> str: # pylint: disable=C0111 if '.' not in name: - full_path = '.'.join([namespace, family, name]) + full_path = '.'.join([family, name]) if namespace == Config['variable_namespace']: self.full_paths_variables[name] = full_path else: @@ -120,10 +129,10 @@ class Path: ) -> 'Variable': # pylint: disable=C0111 variable, suffix = self._get_variable(name, with_suffix=True) if suffix: - raise DictConsistencyError(_("{name} is a dynamic variable"), 36) + raise DictConsistencyError(_(f"{name} is a dynamic variable"), 36) return variable['variableobj'] - def get_variable_family_name(self, + def get_variable_family_path(self, name: str, ) -> str: # pylint: disable=C0111 return self._get_variable(name)['family'] diff --git a/src/rougail/tiramisureflector.py b/src/rougail/tiramisureflector.py index aef03d03..27e919a0 100644 --- a/src/rougail/tiramisureflector.py +++ b/src/rougail/tiramisureflector.py @@ -196,7 +196,7 @@ class Common: def populate_properties(self, child): assert child.type == 'calculation' action = f"ParamValue('{child.name}')" - option_name = self.storage.get(child.source).get() + option_name = self.storage.get(child.source.path).get() kwargs = f"'condition': ParamOption({option_name}, todict=True), 'expected': ParamValue('{child.expected}')" if child.inverse: kwargs += ", 'reverse_condition': ParamValue(True)" diff --git a/tests/test_1_flattener.py b/tests/test_1_flattener.py index 5fb38cc6..51209a2d 100644 --- a/tests/test_1_flattener.py +++ b/tests/test_1_flattener.py @@ -102,7 +102,9 @@ def test_error_dictionary(test_dir_error): 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}' + if err.value.errno != errno: + print(f'expected errno: {errno}, errno: {err.value.errno}') + launch_flattener(test_dir) assert getcwd() == ORI_DIR