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.

Reply via email to