le patch treemixin a été importé stable
authorKatia Saurfelt <katia.saurfelt@logilab.fr>
Thu, 15 Apr 2010 18:30:48 +0200
branchstable
changeset 109 9cc78cbf5813
parent 108 6adea1a62e97
child 110 36d3106df60c
le patch treemixin a été importé
entities.py
hooks.py
test/unittest_descendant_of.py
--- a/entities.py	Thu Apr 15 18:30:30 2010 +0200
+++ b/entities.py	Thu Apr 15 18:30:48 2010 +0200
@@ -6,6 +6,8 @@
 """
 __docformat__ = "restructuredtext en"
 
+from logilab.common.deprecation import  deprecated
+
 from cubicweb.mixins import MI_REL_TRIGGERS, TreeMixIn
 from cubicweb.entities import AnyEntity, fetch_config
 from cubicweb.interfaces import ITree
@@ -44,6 +46,7 @@
         """returns true if this node has no parent"""
         return True
 
+    @deprecated('[3.6] was specific to external project')
     def first_level_keywords(self):
         return self.req.execute('Any K,N ORDERBY N WHERE K included_in C, '
                                 'NOT K subkeyword_of KK, K name N, '
@@ -54,7 +57,6 @@
     __regid__ = 'Keyword'
     fetch_attrs, fetch_order = fetch_config(['name'])
     __implements__ = AnyEntity.__implements__ + (ITree,)
-
     tree_attribute = 'subkeyword_of'
 
     @property
@@ -64,13 +66,16 @@
         return None
 
     def parent(self):
-        """IBreadcrumbs implementation"""
-        if self.subkeyword_of:
-            return self.subkeyword_of[0]
-        return self.classification
+        """ITree + IBreadcrumbs implementation"""
+        try:
+            return self.related(self.tree_attribute, self.parent_target,
+                                entities=True)[0]
+        except (KeyError, IndexError):
+            return self.classification
 
     def iterparents(self):
-        """returns parent keyword entities
+        """returns parent keyword entities,
+           without the root classification
         """
         if self.subkeyword_of:
             parent = self.subkeyword_of[0]
@@ -81,13 +86,6 @@
                 else:
                     parent = None
 
-    def children(self, entities=True):
-        """returns the item's children
-
-        we have only one direct child by ``subkeyword_of`` relation"""
-        assert 1 == len(self.reverse_subkeyword_of)
-        return iter(self.reverse_subkeyword_of)
-
     def iterchildren(self):
         """returns children entities"""
         if self.reverse_subkeyword_of:
@@ -99,24 +97,18 @@
                 else:
                     child = None
 
-    def is_leaf(self):
-        if self.reverse_subkeyword_of:
-            return False
-        return True
-
-    def children_rql(self):
-        return 'Any K WHERE  K subkeyword_of X, X eid %(x)s'
-
-    """
-    # FIXME unittest
-    def subkeywords(self, recursive=True):
-        rset = self.req.execute(self.children_rql(), {'x': self.eid})
-        subentities = list(rset.entities())
-        if recursive:
-            for entity in subentities[:]:
-                subentities.extend(entity.subkeywords(recursive=True))
-        return subentities
-    """
+    def recurse_children(self, _done=None):
+        """returns strict descendents"""
+        if _done is not None and self.eid in _done:
+            return
+        if _done is not None:
+            _done.add(self.eid)
+            yield self
+        else:
+            _done = set()
+        for child in self.children():
+            for entity in child.recurse_children(_done):
+                yield entity
 
 class CodeKeyword(Keyword):
     __regid__ = 'CodeKeyword'
--- a/hooks.py	Thu Apr 15 18:30:30 2010 +0200
+++ b/hooks.py	Thu Apr 15 18:30:48 2010 +0200
@@ -22,7 +22,7 @@
         entity = self._cw.entity_from_eid(self.eidfrom)
         parent = self._cw.entity_from_eid(self.eidto)
         parents = set([x.eid for x in chain([parent,], parent.iterparents())])
-        children = set([x.eid for x in chain([entity], entity.iterchildren())])
+        children = set([x.eid for x in chain([entity], entity.recurse_children())])
         if children & parents:
             msg = _('detected descendant_of cycle')
             raise ValidationError(self.eidfrom, {role_name(self.rtype, 'subject'): msg})
@@ -112,7 +112,7 @@
         entity = self.entity
         parent = self.parent
         for parent in chain([parent, entity], parent.iterparents()):
-            for child in chain([entity], entity.iterchildren()):
+            for child in chain([entity], entity.recurse_children()):
                 if child.eid != parent.eid:
                     closure.add((child, parent))
         for child, parent in closure:
--- a/test/unittest_descendant_of.py	Thu Apr 15 18:30:30 2010 +0200
+++ b/test/unittest_descendant_of.py	Thu Apr 15 18:30:48 2010 +0200
@@ -22,7 +22,7 @@
         self.assertUnorderedIterableEquals([kw.name for kw in child.iterparents()], ['kw4', 'kw3', 'kw2', 'kw1'])
         self.assertUnorderedIterableEquals([kw.name for kw in child.descendant_of], ['kw4', 'kw3', 'kw2', 'kw1'])
         self.assertUnorderedIterableEquals([kw.name for kw in parent.reverse_descendant_of], ['kw5', 'kw4', 'kw3', 'kw2'])
-        self.assertUnorderedIterableEquals([kw.name for kw in parent.iterchildren()], ['kw5', 'kw4', 'kw3', 'kw2'])
+        self.assertUnorderedIterableEquals([kw.name for kw in parent.recurse_children()], ['kw5', 'kw4', 'kw3', 'kw2'])
 
     def test_keyword_add2(self):
         req = self.request()
@@ -40,7 +40,7 @@
         self.assertUnorderedIterableEquals([kw.name for kw in child.iterparents()], ['kw4', 'kw3', 'kw2', 'kw1'])
         self.assertUnorderedIterableEquals([kw.name for kw in child.descendant_of], ['kw4', 'kw3', 'kw2', 'kw1'])
         self.assertUnorderedIterableEquals([kw.name for kw in parent.reverse_descendant_of], ['kw5', 'kw4', 'kw3', 'kw2'])
-        self.assertUnorderedIterableEquals([kw.name for kw in parent.iterchildren()], ['kw5', 'kw4', 'kw3', 'kw2'])
+        self.assertUnorderedIterableEquals([kw.name for kw in parent.recurse_children()], ['kw5', 'kw4', 'kw3', 'kw2'])
 
     def test_keyword_add3(self):
         req = self.request()
@@ -60,7 +60,7 @@
         self.assertUnorderedIterableEquals([kw.name for kw in child.descendant_of], ['kw4', 'kw3', 'kw2', 'kw1'])
         # XXX check the order of iterparents
         self.assertUnorderedIterableEquals([kw.name for kw in child.iterparents()], ['kw4', 'kw3', 'kw2', 'kw1'])
-        self.assertUnorderedIterableEquals([kw.name for kw in parent.iterchildren()], ['kw2', 'kw3', 'kw4', 'kw5'])
+        self.assertUnorderedIterableEquals([kw.name for kw in parent.recurse_children()], ['kw2', 'kw3', 'kw4', 'kw5'])
         self.assertUnorderedIterableEquals([kw.name for kw in parent.reverse_descendant_of], ['kw2', 'kw3', 'kw4', 'kw5'])
 
     def test_keyword_add4(self):
@@ -114,6 +114,30 @@
         kw3.clear_all_caches()
         self.assertUnorderedIterableEquals([kw.name for kw in kw3.descendant_of], ['kw4', 'kw5'])
 
+    def test_keyword_descendant_of(self):
+        req = self.request()
+        kw1 = req.create_entity('Keyword', name=u'kw1', included_in=self.classif1)
+        kw2 = req.create_entity('Keyword', name=u'kw2', subkeyword_of=kw1, included_in=self.classif1)
+        kw3 = req.create_entity('Keyword', name=u'kw3', subkeyword_of=kw1, included_in=self.classif1)
+        self.commit()
+        self.assertUnorderedIterableEquals([kw.name for kw in kw2.descendant_of], ['kw1', ])
+        self.assertUnorderedIterableEquals([kw.name for kw in kw3.descendant_of], ['kw1', ])
+        self.assertUnorderedIterableEquals([kw.name for kw in kw1.reverse_descendant_of], ['kw3', 'kw2'])
+        self.assertUnorderedIterableEquals([kw.name for kw in kw1.recurse_children()], ['kw2', 'kw3'])
+        kw0 = req.create_entity('Keyword', name=u'kw0', included_in=self.classif1)
+        self.execute('SET K1 subkeyword_of K0 WHERE K1 eid %(kw1)s, K0 eid %(kw0)s',
+                      {'kw1': kw1.eid, 'kw0': kw0.eid})
+        self.commit();
+        kw1.clear_all_caches()
+        kw2.clear_all_caches()
+        kw3.clear_all_caches()
+        self.assertUnorderedIterableEquals([kw.name for kw in kw0.recurse_children()], ['kw1', 'kw2', 'kw3'])
+        self.assertUnorderedIterableEquals([kw.name for kw in kw0.reverse_descendant_of], ['kw3', 'kw2', 'kw1'])
+        self.assertUnorderedIterableEquals([kw.name for kw in kw1.descendant_of], ['kw0',])
+        self.assertUnorderedIterableEquals([kw.name for kw in kw2.descendant_of], ['kw1', 'kw0'])
+        self.assertUnorderedIterableEquals([kw.name for kw in kw3.descendant_of], ['kw1', 'kw0'])
+
+
     def test_keyword_delete(self):
         """*after_delete_relation* of ``subkeyword_of``
         """
@@ -130,7 +154,7 @@
         self.assertUnorderedIterableEquals([kw.name for kw in kw3.iterparents()], [])
         self.assertUnorderedIterableEquals([kw.name for kw in kw3.descendant_of], [])
         self.assertUnorderedIterableEquals([kw.name for kw in kw3.reverse_descendant_of], ['kw5', 'kw4'])
-        self.assertUnorderedIterableEquals([kw.name for kw in kw3.iterchildren()], ['kw5', 'kw4'])
+        self.assertUnorderedIterableEquals([kw.name for kw in kw3.recurse_children()], ['kw5', 'kw4'])
 
     def test_no_add_descendant_cycle(self):
         """no ``descendant_of`` cycle"""