On Oct 12, 2013, at 11:54 AM, Marc Van Olmen <marcvanol...@gmail.com> wrote:

> hi,
> 
> Just wanted to quickly report this issue, didn't had time to write unit test 
> for corning the case:
> Was upgrading an 0.4.8 legacy project to 0.8.2
> 
> Got an SAWarning: This collection has been invalidated in the following case:
> 
> Original 0.4.8 code:
> 
>             self._serials.append(MetaSerial(value=u'))
> 
> And failed to add it to the collection.
> 
> The fix needed to get rid of the above warning:
> 
>             a_serial = MetaSerial(value=u'')
>             self._serials.append(a_serial)


there's nothing in the mapping or sample code illustrated here that by itself 
would emit this warning.  The warning itself is not a bug, but instead refers 
to a bug in the calling code, where it is erroneously appending to a collection 
that is no longer valid, due to expiration.  Expiration on session commit was 
introduced as a default behavior in 0.5 and the collection mechanics also 
changed significantly from 0.5 on forward.

The code example you have suggests a premature garbage collection of some 
resource due to the way MetaSerial is not assigned to a variable in one case 
vs. the other, but that's not really possible with a straight append to a 
mapped collection as above, and that also doesn't have any direct path to 
causing this very specific collection-oriented warning from being emitted.  So 
either this code isn't the primary cause of the issue, or there's something 
more complex going on in the actual classes and/or mappings that produces this.

To produce the warning, you have to do something equivalent to the sample code 
below:

from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class A(Base):
    __tablename__ = 'a'

    id = Column(Integer, primary_key=True)
    bs = relationship("B")

class B(Base):
    __tablename__ = 'b'

    id = Column(Integer, primary_key=True)
    a_id = Column(Integer, ForeignKey('a.id'))

e = create_engine("sqlite://", echo=True)

Base.metadata.create_all(e)

sess = Session(e)
a1 = A()
a1.bs = [B()]

# hold onto the collection
collection = a1.bs

sess.add(a1)

# "collection" is now no longer associated with a1
sess.commit()

# emits the warning
collection.append(B())


Attachment: signature.asc
Description: Message signed with OpenPGP using GPGMail

Reply via email to