unpickle event in mutable requires hashing which might hit upon attribute access

Issue #2362 resolved
Mike Bayer repo owner created an issue

e.g.:

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

Base= declarative_base()


class Point(MutableComposite):
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __composite_values__(self):
        return self.x, self.y

    def __getstate__(self):
        return self.x, self.y

    def __setstate__(self, state):
        self.x, self.y = state

    def __setattr__(self, key, value):
        "Intercept set events"

        # set the attribute
        object.__setattr__(self, key, value)

        # alert all parents to the change
        self.changed()

    def __repr__(self):
        return "Point(x=%r, y=%r)" % (self.x, self.y)

    def __eq__(self, other):
        return isinstance(other, Point) and \
            other.x == self.x and \
            other.y == self.y

    def __ne__(self, other):
        return not self.__eq__(other)


class User(Base):
    __tablename__ = 'user'
    id = Column(Integer, primary_key=True)

    data = composite(Point, Column('x', Integer), Column('y', Integer))

    def __eq__(self, other):
        return self.id == other.id

import pickle

u1 = User(data=Point(3, 5))

pickle.loads(pickle.dumps(u1))

output:

Traceback (most recent call last):
  File "test.py", line 57, in <module>
    pickle.loads(pickle.dumps(u1))
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1382, in loads
    return Unpickler(file).load()
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 858, in load
    dispatch[key](key)(self)
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.py", line 1217, in load_build
    setstate(state)
  File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/orm/state.py", line 191, in __setstate__
    manager.dispatch.unpickle(self, state)
  File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/event.py", line 274, in __call__
    fn(*args, **kw)
  File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/ext/mutable.py", line 413, in unpickle
    val._parents[state.obj()](state.obj()) = key
  File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/weakref.py", line 262, in __setitem__
    self.data[self._remove)](ref(key,) = value
  File "test.py", line 51, in __eq__
    return self.id == other.id
  File "/Users/classic/dev/sqlalchemy/lib/sqlalchemy/orm/attributes.py", line 168, in __get__
    return self.impl.get(instance_state(instance),dict_)
AttributeError: 'User' object has no attribute '_sa_instance_state'

simple patch:

diff -r 737456866c5f73452249cec0ccae9e9c4c5c545a lib/sqlalchemy/orm/state.py
--- a/lib/sqlalchemy/orm/state.py   Fri Dec 30 15:29:44 2011 -0500
+++ b/lib/sqlalchemy/orm/state.py   Fri Dec 30 23:56:40 2011 -0500
@@ -187,6 +187,7 @@
         if 'load_path' in state:
             self.load_path = interfaces.deserialize_path(state['load_path']('load_path'))

+        manager.setup_instance(inst, self)
         manager.dispatch.unpickle(self, state)

     def initialize(self, key):

Comments (2)

  1. Log in to comment