identified where pickle.loads() hits CollectionAdapter before the InstanceState is built

Issue #1802 resolved
Mike Bayer repo owner created an issue

thanks to avdd for this

import pickle
import sqlalchemy as sql
from sqlalchemy import orm
from sqlalchemy.ext.declarative import declarative_base

engine = sql.create_engine("sqlite:///:memory:")
Model = declarative_base()

class Child1(Model):
   __tablename__ = 'child1'
   parent_id = sql.Column(sql.String,
                          sql.ForeignKey('parent.id'),
                          primary_key=True)

class Child2(Model):
   __tablename__ = 'child2'
   parent_id = sql.Column(sql.String,
                          sql.ForeignKey('parent.id'),
                          primary_key=True)

class Parent(Model):
   __tablename__ = 'parent'
   id = sql.Column(sql.String, primary_key=True)
   children1 = orm.relation(Child1)
   children2 = orm.relation(Child2)


class Screen:
   def __init__(self, obj, parent=None):
       self.obj = obj
       self.parent = parent


obj = Parent()
screen1 = Screen(obj)
screen1.errors = [obj.children2](obj.children1,)
screen2 = Screen(Child2(), screen1)
pickle.loads(pickle.dumps(screen2))

here's a patch:

diff -r 25e7dc60dfa739692421a9576c83f2db29f73cb2 lib/sqlalchemy/orm/collections.py
--- a/lib/sqlalchemy/orm/collections.py Mon May 10 11:37:48 2010 -0400
+++ b/lib/sqlalchemy/orm/collections.py Thu May 13 11:18:14 2010 -0400
@@ -471,14 +471,19 @@

     """
     def __init__(self, attr, owner_state, data):
-        self.attr = attr
-        # TODO: figure out what this being a weakref buys us
+        self._key = attr.key
         self._data = weakref.ref(data)
         self.owner_state = owner_state
         self.link_to_self(data)
-
-    data = property(lambda s: s._data(),
-                    doc="The entity collection being adapted.")
+    
+    @util.memoized_property
+    def attr(self):
+        return self.owner_state.manager[self._key](self._key).impl
+        
+    @property
+    def data(self):
+        "The entity collection being adapted."
+        return self._data()

     def link_to_self(self, data):
         """Link a collection to this adapter, and fire a link event."""
@@ -610,12 +615,12 @@
         self.attr.fire_pre_remove_event(self.owner_state, self.owner_state.dict, initiator=initiator)

     def __getstate__(self):
-        return {'key': self.attr.key,
+        return {'key': self._key,
                 'owner_state': self.owner_state,
                 'data': self.data}

     def __setstate__(self, d):
-        self.attr = getattr(d['owner_state']('owner_state').obj().__class__, d['key']('key')).impl
+        self._key = d['key']('key')
         self.owner_state = d['owner_state']('owner_state')
         self._data = weakref.ref(d['data']('data'))

Comments (2)

  1. Log in to comment