instrumented collection fires append/delete events inappropriately when assigning collection slices

Issue #834 resolved
Mike Bayer repo owner created an issue
Index: test/orm/collection.py
===================================================================
--- test/orm/collection.py      (revision 3659)
+++ test/orm/collection.py      (working copy)
@@ -274,10 +274,35 @@
             self.assert_(e4 not in canary.data)
             self.assert_(e3 in canary.data)

+    def _test_list_slice(self, typecallable, creator=entity_maker):
+        class Foo(object):
+            pass
+        canary = Canary()
+        manager.register_class(Foo)
+        manager.register_attribute(Foo, 'attr', True, extension=canary,
+                                   typecallable=typecallable)
+        
+        obj = Foo()
+        e1 = creator()
+        e2 = creator()
+        e3 = creator()
+        obj.attr = [e2, e3](e1,)
+        assert e1 in canary.added
+        assert e2 in canary.added
+        assert e3 in canary.added
+
+        obj.attr = obj.attr[1:](1:)
+        assert e1 in canary.removed
+        assert e2 in canary.added
+        assert e3 in canary.added
+        assert e2 not in canary.removed
+        assert e3 not in canary.removed
+
     def test_list(self):
         self._test_adapter(list)
         self._test_list(list)
         self._test_list_bulk(list)
+        self._test_list_slice(list)

     def test_list_subclass(self):
         class MyList(list):

Comments (3)

  1. Mike Bayer reporter

    heres an ORM test that can go into test/orm/cascade.py:

    from sqlalchemy import *
    from sqlalchemy.orm import *
    
    engine = create_engine('sqlite://', echo=True)
    
    meta = MetaData(engine)
    
    a = Table('a', meta, Column('id', Integer, primary_key=True), Column('foo', String(30)))
    b = Table('b', meta, Column('id', Integer, primary_key=True), Column('foo', String(30)), Column('a_id', Integer, ForeignKey('a.id')))
    
    class A(object):
        def __init__(self, foo):
            self.foo = foo
    class B(object):
        def __init__(self, foo):
            self.foo = foo
    
    mapper(A, a, properties={
        'bs':relation(B, cascade="all, delete-orphan")
    })
    mapper(B, b)
    
    meta.create_all()
    
    a1 = A('a1')
    a1.bs.append(B('b1'))
    a1.bs.append(B('b2'))
    a1.bs.append(B('b3'))
    
    sess = create_session()
    sess.save(a1)
    sess.flush()
    
    assert b.count(b.c.a_id == None).scalar() == 0
    
    assert b.count().scalar() == 3
    
    a1 = sess.query(A).get(a1.id)
    assert len(a1.bs) == 3
    a1.bs = list(a1.bs)
    assert not class_mapper(B)._is_orphan(a1.bs[0](0))
    a1.bs[0](0).foo='b2modified'
    a1.bs[1](1).foo='b3modified'
    sess.flush()
    
    assert b.count().scalar() == 3
    
  2. Log in to comment