Ordered list is not correctly ordered on setattr

Issue #3016 invalid
Marc Schlaich created an issue

I have a case where I build a new collection based on some existing elements from the old collection and adding new ones. On setattr the new collections, some elements have already set the order by attribute and some of them not. Here is the issue: only the elements with no order by attribute get a value so after a new query the ordering of the list is wrong.

Test case:

from sqlalchemy import create_engine, Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.orderinglist import ordering_list

Base = declarative_base()


class Slide(Base):
    __tablename__ = 'slide'

    id = Column(Integer, primary_key=True)
    name = Column(String)

    bullets = relationship("Bullet", order_by="Bullet.position",
                           collection_class=ordering_list('position'))


class Bullet(Base):
    __tablename__ = 'bullet'
    id = Column(Integer, primary_key=True)
    slide_id = Column(Integer, ForeignKey('slide.id'))
    position = Column(Integer)
    text = Column(String)


engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)


def test_ordered_list_setattr():
    session = Session()
    s = Slide()
    s.bullets.append(Bullet(text='a'))
    s.bullets.append(Bullet(text='b'))
    session.add(s)
    session.commit()

    s = session.query(Slide).one()
    bullets = list()
    old_bullets = s.bullets[:]
    bullets.append(Bullet(text='c'))
    bullets.extend(old_bullets)
    print [b.position for b in bullets]
    s.bullets = bullets
    session.commit()
    print [b.position for b in bullets]

    s = session.query(Slide).one()
    assert [b.text for b in s.bullets] == ['c', 'a', 'b']

Test run:

$ py.test sqla.py
============================= test session starts =============================
platform win32 -- Python 2.7.6 -- py-1.4.20 -- pytest-2.5.2
collected 1 items

sqla.py F

================================== FAILURES ===================================
__________________________ test_ordered_list_setattr __________________________

    def test_ordered_list_setattr():
        session = Session()
        s = Slide()
        s.bullets.append(Bullet(text='a'))
        s.bullets.append(Bullet(text='b'))
        session.add(s)
        session.commit()

        s = session.query(Slide).one()
        bullets = list()
        old_bullets = s.bullets[:]
        bullets.append(Bullet(text='c'))
        bullets.extend(old_bullets)
        print [b.position for b in bullets]
        s.bullets = bullets
        session.commit()
        print [b.position for b in bullets]

        s = session.query(Slide).one()
>       assert [b.text for b in s.bullets] == ['c', 'a', 'b']
E       assert ['a', 'c', 'b'] == ['c', 'a', 'b']
E         At index 0 diff: u'a' != 'c'

sqla.py:54: AssertionError
------------------------------- Captured stdout -------------------------------
[None, 0, 1]
[0, 0, 1]
========================== 1 failed in 0.27 seconds ===========================

Comments (7)

  1. Marc Schlaich reporter

    note that this operation: object.somelist = [somelist] uses append() for each member individually.

    @zzzeek Exactly this part is not documented.

  2. Log in to comment