[entity] fix cw_instantiate w/ reverse_ relation crash when either multiple entities are given or an eid instead of an entity stable
authorSylvain Thénault <sylvain.thenault@logilab.fr>
Fri, 13 May 2011 10:09:54 +0200
branchstable
changeset 7376 38524ca653e5
parent 7375 c8a8fb32733b
child 7377 d8083b2ae4d6
child 7384 69aa88765db5
[entity] fix cw_instantiate w/ reverse_ relation crash when either multiple entities are given or an eid instead of an entity
devtools/testlib.py
entity.py
test/unittest_entity.py
--- a/devtools/testlib.py	Fri May 13 10:09:52 2011 +0200
+++ b/devtools/testlib.py	Fri May 13 10:09:54 2011 +0200
@@ -495,6 +495,10 @@
         entity.cw_attr_cache.pop('modification_date', None)
         self.failUnless(entity.modification_date > olddate)
 
+    def assertItemsEqual(self, it1, it2, *args, **kwargs):
+        it1 = set(getattr(x, 'eid', x) for x in it1)
+        it2 = set(getattr(x, 'eid', x) for x in it2)
+        super(CubicWebTC, self).assertItemsEqual(it1, it2, *args, **kwargs)
 
     # workflow utilities #######################################################
 
--- a/entity.py	Fri May 13 10:09:52 2011 +0200
+++ b/entity.py	Fri May 13 10:09:54 2011 +0200
@@ -270,6 +270,7 @@
         restrictions = set()
         pending_relations = []
         eschema = cls.e_schema
+        qargs = {}
         for attr, value in kwargs.items():
             if attr.startswith('reverse_'):
                 attr = attr[len('reverse_'):]
@@ -283,10 +284,11 @@
                     value = iter(value).next()
                 else:
                     # prepare IN clause
-                    del kwargs[attr]
-                    pending_relations.append( (attr, value) )
+                    pending_relations.append( (attr, role, value) )
                     continue
-            if hasattr(value, 'eid'): # non final relation
+            if rschema.final: # attribute
+                relations.append('X %s %%(%s)s' % (attr, attr))
+            else:
                 rvar = attr.upper()
                 if role == 'object':
                     relations.append('%s %s X' % (rvar, attr))
@@ -295,21 +297,21 @@
                 restriction = '%s eid %%(%s)s' % (rvar, attr)
                 if not restriction in restrictions:
                     restrictions.add(restriction)
-                kwargs[attr] = value.eid
-            else: # attribute
-                relations.append('X %s %%(%s)s' % (attr, attr))
+                if hasattr(value, 'eid'):
+                    value = value.eid
+            qargs[attr] = value
         if relations:
             rql = '%s: %s' % (rql, ', '.join(relations))
         if restrictions:
             rql = '%s WHERE %s' % (rql, ', '.join(restrictions))
-        created = execute(rql, kwargs).get_entity(0, 0)
-        for attr, values in pending_relations:
-            if attr.startswith('reverse_'):
-                restr = 'Y %s X' % attr[len('reverse_'):]
+        created = execute(rql, qargs).get_entity(0, 0)
+        for attr, role, values in pending_relations:
+            if role == 'object':
+                restr = 'Y %s X' % attr
             else:
                 restr = 'X %s Y' % attr
             execute('SET %s WHERE X eid %%(x)s, Y eid IN (%s)' % (
-                restr, ','.join(str(r.eid) for r in values)),
+                restr, ','.join(str(getattr(r, 'eid', r)) for r in values)),
                     {'x': created.eid}, build_descr=False)
         return created
 
--- a/test/unittest_entity.py	Fri May 13 10:09:52 2011 +0200
+++ b/test/unittest_entity.py	Fri May 13 10:09:54 2011 +0200
@@ -139,6 +139,27 @@
         self.assertEqual(len(p.related('tags', 'object', limit=2)), 2)
         self.assertEqual(len(p.related('tags', 'object')), 4)
 
+    def test_cw_instantiate_relation(self):
+        req = self.request()
+        p1 = req.create_entity('Personne', nom=u'di')
+        p2 = req.create_entity('Personne', nom=u'mascio')
+        t = req.create_entity('Tag', name=u't1', tags=p1)
+        self.assertItemsEqual(t.tags, [p1])
+        t = req.create_entity('Tag', name=u't2', tags=p1.eid)
+        self.assertItemsEqual(t.tags, [p1])
+        t = req.create_entity('Tag', name=u't3', tags=[p1, p2.eid])
+        self.assertItemsEqual(t.tags, [p1, p2])
+
+    def test_cw_instantiate_reverse_relation(self):
+        req = self.request()
+        t1 = req.create_entity('Tag', name=u't1')
+        t2 = req.create_entity('Tag', name=u't2')
+        p = req.create_entity('Personne', nom=u'di mascio', reverse_tags=t1)
+        self.assertItemsEqual(p.reverse_tags, [t1])
+        p = req.create_entity('Personne', nom=u'di mascio', reverse_tags=t1.eid)
+        self.assertItemsEqual(p.reverse_tags, [t1])
+        p = req.create_entity('Personne', nom=u'di mascio', reverse_tags=[t1, t2.eid])
+        self.assertItemsEqual(p.reverse_tags, [t1, t2])
 
     def test_fetch_rql(self):
         user = self.user()