[PATCH 1 of 1 seda] [schema] Fix iter_all_rdefs utility function to skip rdef not reachable from the container

Sylvain Thenault sylvain.thenault at logilab.fr
Fri Mar 24 10:52:51 CET 2017


# HG changeset patch
# User Sylvain Thénault <sylvain.thenault at logilab.fr>
# Date 1490266746 -3600
#      Thu Mar 23 11:59:06 2017 +0100
# Node ID d3dee90b918300264d97ab0921adbc35b367cd22
# Parent  b91f4a405baf2ba09744d97b84a67532bbef4293
[schema] Fix iter_all_rdefs utility function to skip rdef not reachable from the container

The previous implementation was yielding rdefs which were not in the compound
graph, because of the blind loop on every rdef of an rtype.

To fix this, we can't use structure_def whose data structure isn't adapted to
this use-case, rather iterate top-down from the root (this 'child_structure'
method is unfortunatly not in compound.Graph, we might add it there at some
point).

diff --git a/cubicweb_seda/__init__.py b/cubicweb_seda/__init__.py
--- a/cubicweb_seda/__init__.py
+++ b/cubicweb_seda/__init__.py
@@ -16,13 +16,11 @@
 """cubicweb-seda application package
 
 Data Exchange Standard for Archival
 """
 
-from cubicweb import neg_role
-
-from cubicweb_compound import structure_def, skip_rtypes_set
+from cubicweb_compound import structure_def, skip_rtypes_set, CompositeGraph
 
 
 def seda_profile_container_def(schema):
     """Define container for SEDAProfile"""
     return structure_def(schema, 'SEDAArchiveTransfer').items()
@@ -44,13 +42,24 @@ def iter_external_rdefs(eschema, skip_rt
 
 def iter_all_rdefs(schema, container_etype):
     """Return an iterator on (rdef, role) of all relations of the compound graph starting from the
     given entity type, both internal (composite) and external (non-composite).
     """
-    for etype, parent_rdefs in structure_def(schema, container_etype).items():
-        for rtype, role in parent_rdefs:
-            for rdef in schema[rtype].rdefs.values():
-                yield rdef, neg_role(role)
+    graph = CompositeGraph(schema)
+    stack = [container_etype]
+    visited = set(stack)
+    while stack:
+        etype = stack.pop()
+        for (rtype, role), targets in graph.child_relations(etype):
+            rschema = schema.rschema(rtype)
+            for target in targets:
+                if role == 'subject':
+                    rdef = rschema.rdefs[(etype, target)]
+                else:
+                    rdef = rschema.rdefs[(target, etype)]
+                yield rdef, role
+
+                if target not in visited:
+                    visited.add(target)
+                    stack.append(target)
         for rdef, role in iter_external_rdefs(schema[etype]):
-                yield rdef, role
-    for rdef, role in iter_external_rdefs(schema[container_etype]):
-        yield rdef, role
+            yield rdef, role
diff --git a/test/test_schema.py b/test/test_schema.py
--- a/test/test_schema.py
+++ b/test/test_schema.py
@@ -19,14 +19,17 @@ from contextlib import contextmanager
 
 from cubicweb import ValidationError, Unauthorized
 from cubicweb.devtools.testlib import CubicWebTC
 from cubicweb.schema import ERQLExpression, RRQLExpression
 
+from cubicweb_seda import iter_all_rdefs
+
 import testutils
 
 
 class SchemaConceptConstraintsTC(CubicWebTC):
+
     def setup_database(self):
         with self.admin_access.client_cnx() as cnx:
             mt_scheme = testutils.scheme_for_type(cnx, 'seda_mime_type_to', None)
             mt_concept = mt_scheme.add_concept(label=u'text/plain')
             enc_scheme = testutils.scheme_for_type(cnx, 'seda_encoding_to', None)
@@ -362,8 +365,22 @@ class SecurityTC(CubicWebTC):
             cloned.cw_clear_all_caches()
 
             self.assertTrue(cloned.first_level_choice.content_sequence)
 
 
+class SchemaIteratorTC(CubicWebTC):
+
+    def test_iter_all_rdefs(self):
+        values = {str(rdef) for rdef, role in iter_all_rdefs(self.schema, 'SEDABinaryDataObject')}
+        # composite relation
+        self.assertIn('relation SEDACreatingOs seda_creating_os SEDABinaryDataObject', values)
+        # external relation
+        self.assertIn('relation SEDARelationship seda_type_relationship Concept', values)
+        # outside this compound graph
+        self.assertNotIn(
+            'relation SEDADataObjectVersion seda_data_object_version_from SEDAPhysicalDataObject',
+            values)
+
+
 if __name__ == '__main__':
     import unittest
     unittest.main()


More information about the saem-devel mailing list