On Tuesday, December 27, 2011 7:22:03 AM UTC-8, Michael Bayer wrote: > > > On Dec 27, 2011, at 4:54 AM, Arturo Sevilla wrote: > > > Thanks for the code, your example runs without a problem. > > > > I've managed to "locate" the error. In reality it doesn't have to do > with InstrumentedList. The problem occurs when beaker pickle.load()s from > its cache file (a pickled object in a file). > > I get the following exception (which makes beaker stop loading the > session): AttributeError: 'User' object has no attribute > '_sa_instance_state' > > That means User wasn't mapped when the object was created. This is one of > many reasons I've been encouraging declarative as the standard way to go > these days, so that you can't create a class without it being mapped at > once. > I tried doing class_mapper(User) before the creation of the object. According to the docs if such class is not mapped, then an exception should be raised. I never got such exception so I assume the class is mapped before any (mapped) instance is created. This makes sense as the mapper is called when the import is done.
> > > > If I try to load the file directly I get the same result. > > > > I've been trying to google such error but all I get the reference to is > that orm.mapper() should be run in the thread or process that is loading > the pickled object. I tried loading "manually" (in a python console) my > mappers and the trying to unpickle the object without success. > > mapper() needs to be run in the process, and should be run in the "main" > thread before any worker threads are spawned. It should ideally be part of > module import, or at the very least a "right after import" initialization > step. > > The User object itself must be mapped before the original one is ever > created, before it is ever pickled in the first place. If it doesn't have > a state, it means it was not mapped when pickled. > > > > > I cannot (at the moment) include a code example because it is a medium > sized pylons project. I know that this was working with version 0.6, with > orm.synonym; the main difference is that now I use @hybrid_property and > version 0.7.4. > > I can't think of a way that @synonym by itself would affect this. > Changing back to @synonym in 0.7.4 does what ? > I don't think so either. However I noticed that the error occurred when SQLAlchemy was restoring the '_parents' attribute of a MutableComposite property that the User class has. I have read the docs, and I know that '_parents' should be popped from __dict__ in __getstate__() In fact, I took your code and modified to include a MutableComposite property in the tables. I don't get my exception, but I do get an error while loading from the pickled version (in a similar fashion with my original problem). from sqlalchemy import * from sqlalchemy.orm import * from sqlalchemy.ext.mutable import MutableComposite class User(object): def __init__(self, companies, name): self.companies = companies self.com_name = name class Company(object): pass class NameComposite(MutableComposite): def __init__(self, name, last_name): self.name = name self.last_name = last_name def __composite_values__(self): return self.name, self.last_name def __getstate__(self): copy_dict = self.__dict__.copy() copy_dict.pop('_parents', None) return copy_dict def __setattr__(self, key, value): object.__setattr__(self, key, value) self.changed() def __eq__(self, other): return isinstance(other, NameComposite) and \ other.name == self.name and \ other.last_name == self.last_name def __ne__(self, other): return not self.__eq__(other) metadata = MetaData() user_table = Table('user', metadata, Column('id', Integer, primary_key=True), Column('name', String(100), nullable=False), Column('last_name', String(100), nullable=False), ) company_table = Table('company', metadata, Column('id', Integer, primary_key=True), Column('user_id', Integer, ForeignKey('user.id')) ) mapper(User, user_table, properties={ 'com_name': composite(NameComposite, user_table.c.name, user_table.c.last_name ), 'companies': relationship(Company, backref='_admin') }) mapper(Company, company_table) e = create_engine("sqlite://", echo=True) metadata.create_all(e) s = Session(e) user = User(companies=[Company(), Company(), Company()], name=NameComposite('name', 'last name')) s.add_all([ user ]) s.commit() import cPickle dumped = cPickle.dumps(user) assert cPickle.loads(dumped).id == 1 # ERROR I get "sqlalchemy.orm.exc.DetachedInstanceError: Instance <User at 0x1405dd0> is not bound to a Session; attribute refresh operation cannot proceed" As the error informs me, I tried by doing s.add(user) and s.merge(user) before the dumps() call without success. If it is of any use my original error occurs in here: File "/lib/python2.6/site-packages/SQLAlchemy-0.7.4-py2.6-linux-x86_64.egg/sqlalchemy/ext/mutable.py", line 413, in unpickle val._parents[state.obj()] = key File "/usr/lib/python2.6/weakref.py", line 249, in __setitem__ self.data[ref(key, self._remove)] = value File "/model/base.py", line 230, in __eq__ # This are my files (I have a base class for all my entities with a __eq__ method) return self._get_id() == other._get_id() File "/model/base.py", line 274, in _get_id # Still in the same class return self.id File "/lib/python2.6/site-packages/SQLAlchemy-0.7.4-py2.6-linux-x86_64.egg/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' Thanks -- You received this message because you are subscribed to the Google Groups "sqlalchemy" group. To view this discussion on the web visit https://groups.google.com/d/msg/sqlalchemy/-/2zEBipguafAJ. To post to this group, send email to sqlalchemy@googlegroups.com. To unsubscribe from this group, send email to sqlalchemy+unsubscr...@googlegroups.com. For more options, visit this group at http://groups.google.com/group/sqlalchemy?hl=en.