# HG changeset patch # User Denis Laxalde <denis.laxalde@logilab.fr> # Date 1437142156 -7200 # Fri Jul 17 16:09:16 2015 +0200 # Node ID 12bde733d7b204c2c8384bb97883ed55e5cb3eec # Parent c9088752d968cc6daed76360e629e4cb885c7edd Add parent_structure method to CompositeGraph This method returns a dictionary mapping entity type to composite relation information allowing to walk the schema graph upstream from these entity types. diff --git a/entities.py b/entities.py --- a/entities.py +++ b/entities.py @@ -112,24 +112,31 @@ if children: yield relation, children - def parent_structure(self, etype): - """Return the parent structure of the graph from `etype`.""" - return self._structure(etype, False) + def parent_structure(self, etype, _visited=None): + """Return the parent structure of the graph from `etype`. - def child_structure(self, etype): - """Return the child structure of the graph from `etype`.""" - return self._structure(etype, True) + The structure is a dictionary mapping entity type in the graph with + root `etype` to relation information allowing to walk the graph + upstream from this entity type. + """ + if _visited is None: + _visited = set() + structure = {} - def _structure(self, etype, topdown): - """Return a nested-dict structure obtained from walking the graph of - schema objects from any `parent` entity type in the graph. - """ - graph = {} - for relation, children in self._composite_relations(etype, topdown): + def update_structure(left, relation, right): + structure.setdefault(left, {}).setdefault(relation, []).append(right) + + for (rtype, role), children in self.child_relations(etype): for child in sorted(children): - graph.setdefault(relation, {})[child] = self._structure( - child, topdown) - return graph + update_structure(child, (rtype, neg_role(role)), etype) + if child in _visited: + continue + _visited.add(child) + for left, rels in self.parent_structure(child, _visited).iteritems(): + for relation, rights in rels.iteritems(): + for right in rights: + update_structure(left, relation, right) + return structure def topdown_definition(self, parent): """Return the container definition of the composite graph from diff --git a/test/test_compound.py b/test/test_compound.py --- a/test/test_compound.py +++ b/test/test_compound.py @@ -55,71 +55,42 @@ [(('relates', 'object'), ['Anecdote']), (('event', 'object'), ['Biography'])]) - def test_parent_structure_singleton(self): + def test_parent_structure_agent(self): graph = CompositeGraph(self.schema) - structure = graph.parent_structure('OnlineAccount') - expected = {('account', 'object'): {'Agent': {}}} - self.assertEqual(structure, expected) - - def test_child_structure_singleton(self): - graph = CompositeGraph(self.schema) - structure = graph.child_structure('OnlineAccount') - self.assertEqual(structure, {}) - - def test_child_structure(self): - graph = CompositeGraph(self.schema) - structure = graph.child_structure('Agent') + structure = graph.parent_structure('Agent') expected = { - ('account', 'subject'): { - 'OnlineAccount': {} + 'OnlineAccount': { + ('account', 'object'): ['Agent'], + }, + 'Biography': { + ('biography', 'object'): ['Agent'], }, - ('biography', 'subject'): { - 'Biography': { - ('event', 'subject'): { - 'Event': {}, - 'Anecdote': { - ('relates', 'subject'): - {'Event': {}} - }, - }, - }, + 'Event': { + ('event', 'object'): ['Biography'], + ('relates', 'object'): ['Anecdote'], }, - ('narrated_by', 'object'): { - 'Anecdote': { - ('relates', 'subject'): - {'Event': {}} - }, + 'Anecdote': { + ('event', 'object'): ['Biography'], + ('narrated_by', 'subject'): ['Agent'], }, } self.assertEqual(structure, expected) - def test_parent_structure(self): + def test_parent_structure_anecdote(self): graph = CompositeGraph(self.schema) + self.set_description('Anecdote') structure = graph.parent_structure('Anecdote') - self.assertEqual(structure, { - ('event', 'object'): {'Biography': { - ('biography', 'object'): {'Agent': {}}, - }}, - ('narrated_by', 'subject'): {'Agent': {}}, - }) - structure = graph.parent_structure('Event') - self.assertEqual(structure, { - ('event', 'object'): { - 'Biography': {('biography', 'object'): {'Agent': {}}} + expected = { + 'Event': { + ('relates', 'object'): ['Anecdote'], }, - ('relates', 'object'): { - 'Anecdote': { - ('event', 'object'): { - 'Biography': { - ('biography', 'object'): {'Agent': {}}, - }, - }, - ('narrated_by', 'subject'): {'Agent': {}}, - }, - }, - }) + } + self.assertEqual(structure, expected) + + def test_parent_structure_leaf(self): + graph = CompositeGraph(self.schema) structure = graph.parent_structure('OnlineAccount') - self.assertEqual(structure, {('account', 'object'): {'Agent': {}}}) + self.assertEqual(structure, {}) def test_topdown_definition(self): graph = CompositeGraph(self.schema)